1 /* 2 * PROJECT: ReactOS Task Manager 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Graph plotting controls 5 * COPYRIGHT: Copyright 2002 Robert Dickenson <robd@reactos.org> 6 * Copyright 2021 Wu Haotian <rigoligo03@gmail.com> 7 */ 8 9 #include "precomp.h" 10 11 #include <math.h> 12 13 WNDPROC OldGraphCtrlWndProc; 14 15 static void GraphCtrl_Init(TGraphCtrl* this) 16 { 17 int i; 18 19 this->m_hWnd = 0; 20 this->m_hParentWnd = 0; 21 this->m_dcGrid = 0; 22 this->m_dcPlot = 0; 23 this->m_bitmapOldGrid = 0; 24 this->m_bitmapOldPlot = 0; 25 this->m_bitmapGrid = 0; 26 this->m_bitmapPlot = 0; 27 this->m_brushBack = 0; 28 29 this->m_penPlot[0] = 0; 30 this->m_penPlot[1] = 0; 31 this->m_penPlot[2] = 0; 32 this->m_penPlot[3] = 0; 33 34 /* since plotting is based on a LineTo for each new point 35 * we need a starting point (i.e. a "previous" point) 36 * use 0.0 as the default first point. 37 * these are public member variables, and can be changed outside 38 * (after construction). Therefore m_perviousPosition could be set to 39 * a more appropriate value prior to the first call to SetPosition. 40 */ 41 this->m_dPreviousPosition[0] = 0.0; 42 this->m_dPreviousPosition[1] = 0.0; 43 this->m_dPreviousPosition[2] = 0.0; 44 this->m_dPreviousPosition[3] = 0.0; 45 46 /* public variable for the number of decimal places on the y axis */ 47 this->m_nYDecimals = 3; 48 49 /* set some initial values for the scaling until "SetRange" is called. 50 * these are protected variables and must be set with SetRange 51 * in order to ensure that m_dRange is updated accordingly 52 */ 53 /* m_dLowerLimit = -10.0; */ 54 /* m_dUpperLimit = 10.0; */ 55 this->m_dLowerLimit = 0.0; 56 this->m_dUpperLimit = 100.0; 57 this->m_dRange = this->m_dUpperLimit - this->m_dLowerLimit; /* protected member variable */ 58 59 /* m_nShiftPixels determines how much the plot shifts (in terms of pixels) */ 60 /* with the addition of a new data point */ 61 this->m_nShiftPixels = 4; 62 this->m_nHalfShiftPixels = this->m_nShiftPixels / 2; /* protected */ 63 this->m_nPlotShiftPixels = this->m_nShiftPixels + this->m_nHalfShiftPixels; /* protected */ 64 65 /* Set how big the grid boxes are */ 66 this->m_nGridXPixels = 12; 67 this->m_nGridYPixels = 12; 68 69 /* Task manager should scroll grid with the graph. This variable contains the */ 70 /* amount of pixels the grid paint origin should shift to left */ 71 this->m_nGridOffsetPixels = 0; 72 73 /* background, grid and data colors */ 74 /* these are public variables and can be set directly */ 75 this->m_crBackColor = RGB( 0, 0, 0); /* see also SetBackgroundColor */ 76 this->m_crGridColor = RGB( 0, 128, 64); /* see also SetGridColor */ 77 this->m_crPlotColor[0] = RGB(255, 255, 255); /* see also SetPlotColor */ 78 this->m_crPlotColor[1] = RGB(100, 255, 255); /* see also SetPlotColor */ 79 this->m_crPlotColor[2] = RGB(255, 100, 255); /* see also SetPlotColor */ 80 this->m_crPlotColor[3] = RGB(255, 255, 100); /* see also SetPlotColor */ 81 82 /* protected variables */ 83 for (i = 0; i < MAX_PLOTS; i++) 84 { 85 this->m_penPlot[i] = CreatePen(PS_SOLID, 0, this->m_crPlotColor[i]); 86 } 87 this->m_brushBack = CreateSolidBrush(this->m_crBackColor); 88 89 /* public member variables, can be set directly */ 90 strcpy(this->m_strXUnitsString, "Samples"); /* can also be set with SetXUnits */ 91 strcpy(this->m_strYUnitsString, "Y units"); /* can also be set with SetYUnits */ 92 93 /* protected bitmaps to restore the memory DC's */ 94 this->m_bitmapOldGrid = NULL; 95 this->m_bitmapOldPlot = NULL; 96 } 97 98 void GraphCtrl_Dispose(TGraphCtrl* this) 99 { 100 int plot; 101 102 for (plot = 0; plot < MAX_PLOTS; plot++) 103 DeleteObject(this->m_penPlot[plot]); 104 105 /* just to be picky restore the bitmaps for the two memory dc's */ 106 /* (these dc's are being destroyed so there shouldn't be any leaks) */ 107 108 if (this->m_bitmapOldGrid != NULL) SelectObject(this->m_dcGrid, this->m_bitmapOldGrid); 109 if (this->m_bitmapOldPlot != NULL) SelectObject(this->m_dcPlot, this->m_bitmapOldPlot); 110 if (this->m_bitmapGrid != NULL) DeleteObject(this->m_bitmapGrid); 111 if (this->m_bitmapPlot != NULL) DeleteObject(this->m_bitmapPlot); 112 if (this->m_dcGrid != NULL) DeleteDC(this->m_dcGrid); 113 if (this->m_dcPlot != NULL) DeleteDC(this->m_dcPlot); 114 if (this->m_brushBack != NULL) DeleteObject(this->m_brushBack); 115 } 116 117 void GraphCtrl_Create(TGraphCtrl* this, HWND hWnd, HWND hParentWnd, UINT nID) 118 { 119 GraphCtrl_Init(this); 120 this->m_hParentWnd = hParentWnd; 121 this->m_hWnd = hWnd; 122 123 GraphCtrl_Resize(this); 124 125 return; 126 } 127 128 void GraphCtrl_SetRange(TGraphCtrl* this, double dLower, double dUpper, int nDecimalPlaces) 129 { 130 /* ASSERT(dUpper > dLower); */ 131 this->m_dLowerLimit = dLower; 132 this->m_dUpperLimit = dUpper; 133 this->m_nYDecimals = nDecimalPlaces; 134 this->m_dRange = this->m_dUpperLimit - this->m_dLowerLimit; 135 this->m_dVerticalFactor = (double)this->m_nPlotHeight / this->m_dRange; 136 /* clear out the existing garbage, re-start with a clean plot */ 137 GraphCtrl_InvalidateCtrl(this, FALSE); 138 } 139 140 #if 0 141 void TGraphCtrl::SetXUnits(const char* string) 142 { 143 strncpy(m_strXUnitsString, string, sizeof(m_strXUnitsString) - 1); 144 /* clear out the existing garbage, re-start with a clean plot */ 145 InvalidateCtrl(); 146 } 147 148 void TGraphCtrl::SetYUnits(const char* string) 149 { 150 strncpy(m_strYUnitsString, string, sizeof(m_strYUnitsString) - 1); 151 /* clear out the existing garbage, re-start with a clean plot */ 152 InvalidateCtrl(); 153 } 154 #endif 155 156 void GraphCtrl_SetGridColor(TGraphCtrl* this, COLORREF color) 157 { 158 this->m_crGridColor = color; 159 /* clear out the existing garbage, re-start with a clean plot */ 160 GraphCtrl_InvalidateCtrl(this, FALSE); 161 } 162 163 void GraphCtrl_SetPlotColor(TGraphCtrl* this, int plot, COLORREF color) 164 { 165 this->m_crPlotColor[plot] = color; 166 DeleteObject(this->m_penPlot[plot]); 167 this->m_penPlot[plot] = CreatePen(PS_SOLID, 0, this->m_crPlotColor[plot]); 168 /* clear out the existing garbage, re-start with a clean plot */ 169 GraphCtrl_InvalidateCtrl(this, FALSE); 170 } 171 172 void GraphCtrl_SetBackgroundColor(TGraphCtrl* this, COLORREF color) 173 { 174 this->m_crBackColor = color; 175 DeleteObject(this->m_brushBack); 176 this->m_brushBack = CreateSolidBrush(this->m_crBackColor); 177 /* clear out the existing garbage, re-start with a clean plot */ 178 GraphCtrl_InvalidateCtrl(this, FALSE); 179 } 180 181 void GraphCtrl_InvalidateCtrl(TGraphCtrl* this, BOOL bResize) 182 { 183 /* There is a lot of drawing going on here - particularly in terms of */ 184 /* drawing the grid. Don't panic, this is all being drawn (only once) */ 185 /* to a bitmap. The result is then BitBlt'd to the control whenever needed. */ 186 int i; 187 int nCharacters; 188 //int nTopGridPix, nMidGridPix, nBottomGridPix; 189 190 HPEN oldPen; 191 HPEN solidPen = CreatePen(PS_SOLID, 0, this->m_crGridColor); 192 /* HFONT axisFont, yUnitFont, oldFont; */ 193 /* char strTemp[50]; */ 194 195 /* in case we haven't established the memory dc's */ 196 /* CClientDC dc(this); */ 197 HDC dc = GetDC(this->m_hParentWnd); 198 199 /* if we don't have one yet, set up a memory dc for the grid */ 200 if (this->m_dcGrid == NULL) 201 { 202 this->m_dcGrid = CreateCompatibleDC(dc); 203 this->m_bitmapGrid = CreateCompatibleBitmap(dc, this->m_nClientWidth, this->m_nClientHeight); 204 this->m_bitmapOldGrid = (HBITMAP)SelectObject(this->m_dcGrid, this->m_bitmapGrid); 205 } 206 else if(bResize) 207 { 208 // the size of the drawing area has changed 209 // so create a new bitmap of the appropriate size 210 if(this->m_bitmapGrid != NULL) 211 { 212 this->m_bitmapGrid = (HBITMAP)SelectObject(this->m_dcGrid, this->m_bitmapOldGrid); 213 DeleteObject(this->m_bitmapGrid); 214 this->m_bitmapGrid = CreateCompatibleBitmap(dc, this->m_nClientWidth, this->m_nClientHeight); 215 SelectObject(this->m_dcGrid, this->m_bitmapGrid); 216 } 217 } 218 219 SetBkColor(this->m_dcGrid, this->m_crBackColor); 220 221 /* fill the grid background */ 222 FillRect(this->m_dcGrid, &this->m_rectClient, this->m_brushBack); 223 224 /* draw the plot rectangle: */ 225 /* determine how wide the y axis scaling values are */ 226 nCharacters = abs((int)log10(fabs(this->m_dUpperLimit))); 227 nCharacters = max(nCharacters, abs((int)log10(fabs(this->m_dLowerLimit)))); 228 229 /* add the units digit, decimal point and a minus sign, and an extra space */ 230 /* as well as the number of decimal places to display */ 231 nCharacters = nCharacters + 4 + this->m_nYDecimals; 232 233 /* adjust the plot rectangle dimensions */ 234 /* assume 6 pixels per character (this may need to be adjusted) */ 235 /* m_rectPlot.left = m_rectClient.left + 6*(nCharacters); */ 236 this->m_rectPlot.left = this->m_rectClient.left; 237 this->m_nPlotWidth = this->m_rectPlot.right - this->m_rectPlot.left;/* m_rectPlot.Width(); */ 238 239 /* draw the plot rectangle */ 240 oldPen = (HPEN)SelectObject(this->m_dcGrid, solidPen); 241 MoveToEx(this->m_dcGrid, this->m_rectPlot.left, this->m_rectPlot.top, NULL); 242 LineTo(this->m_dcGrid, this->m_rectPlot.right + 1, this->m_rectPlot.top); 243 LineTo(this->m_dcGrid, this->m_rectPlot.right + 1, this->m_rectPlot.bottom + 1); 244 LineTo(this->m_dcGrid, this->m_rectPlot.left, this->m_rectPlot.bottom + 1); 245 /* LineTo(m_dcGrid, m_rectPlot.left, m_rectPlot.top); */ 246 247 /* draw the horizontal axis */ 248 for (i = this->m_rectPlot.top; i <= this->m_rectPlot.bottom; i += this->m_nGridYPixels) 249 { 250 MoveToEx(this->m_dcGrid, this->m_rectPlot.left, i, NULL); 251 LineTo(this->m_dcGrid, this->m_rectPlot.right, i); 252 } 253 254 /* draw the vertical axis */ 255 /* In order to keep grid position uniform when resizing, vertical axis should be */ 256 /* drawn from right to left */ 257 for (i = this->m_rectPlot.right - this->m_nGridOffsetPixels; i >= this->m_rectPlot.left; i -= this->m_nGridXPixels) 258 { 259 MoveToEx(this->m_dcGrid, i, this->m_rectPlot.bottom, NULL); 260 LineTo(this->m_dcGrid, i, this->m_rectPlot.top); 261 } 262 263 SelectObject(this->m_dcGrid, oldPen); 264 DeleteObject(solidPen); 265 266 #if 0 267 /* create some fonts (horizontal and vertical) */ 268 /* use a height of 14 pixels and 300 weight */ 269 /* (these may need to be adjusted depending on the display) */ 270 axisFont = CreateFont (14, 0, 0, 0, 300, 271 FALSE, FALSE, 0, ANSI_CHARSET, 272 OUT_DEFAULT_PRECIS, 273 CLIP_DEFAULT_PRECIS, 274 DEFAULT_QUALITY, 275 DEFAULT_PITCH|FF_SWISS, "Arial"); 276 yUnitFont = CreateFont (14, 0, 900, 0, 300, 277 FALSE, FALSE, 0, ANSI_CHARSET, 278 OUT_DEFAULT_PRECIS, 279 CLIP_DEFAULT_PRECIS, 280 DEFAULT_QUALITY, 281 DEFAULT_PITCH|FF_SWISS, "Arial"); 282 283 /* grab the horizontal font */ 284 oldFont = (HFONT)SelectObject(m_dcGrid, axisFont); 285 286 /* y max */ 287 SetTextColor(m_dcGrid, m_crGridColor); 288 SetTextAlign(m_dcGrid, TA_RIGHT|TA_TOP); 289 sprintf(strTemp, "%.*lf", m_nYDecimals, m_dUpperLimit); 290 TextOut(m_dcGrid, m_rectPlot.left-4, m_rectPlot.top, strTemp, wcslen(strTemp)); 291 292 /* y min */ 293 SetTextAlign(m_dcGrid, TA_RIGHT|TA_BASELINE); 294 sprintf(strTemp, "%.*lf", m_nYDecimals, m_dLowerLimit); 295 TextOut(m_dcGrid, m_rectPlot.left-4, m_rectPlot.bottom, strTemp, wcslen(strTemp)); 296 297 /* x min */ 298 SetTextAlign(m_dcGrid, TA_LEFT|TA_TOP); 299 TextOut(m_dcGrid, m_rectPlot.left, m_rectPlot.bottom+4, "0", 1); 300 301 /* x max */ 302 SetTextAlign(m_dcGrid, TA_RIGHT|TA_TOP); 303 sprintf(strTemp, "%d", m_nPlotWidth/m_nShiftPixels); 304 TextOut(m_dcGrid, m_rectPlot.right, m_rectPlot.bottom+4, strTemp, wcslen(strTemp)); 305 306 /* x units */ 307 SetTextAlign(m_dcGrid, TA_CENTER|TA_TOP); 308 TextOut(m_dcGrid, (m_rectPlot.left+m_rectPlot.right)/2, 309 m_rectPlot.bottom+4, m_strXUnitsString, wcslen(m_strXUnitsString)); 310 311 /* restore the font */ 312 SelectObject(m_dcGrid, oldFont); 313 314 /* y units */ 315 oldFont = (HFONT)SelectObject(m_dcGrid, yUnitFont); 316 SetTextAlign(m_dcGrid, TA_CENTER|TA_BASELINE); 317 TextOut(m_dcGrid, (m_rectClient.left+m_rectPlot.left)/2, 318 (m_rectPlot.bottom+m_rectPlot.top)/2, m_strYUnitsString, wcslen(m_strYUnitsString)); 319 SelectObject(m_dcGrid, oldFont); 320 #endif 321 /* at this point we are done filling the grid bitmap, */ 322 /* no more drawing to this bitmap is needed until the settings are changed */ 323 324 /* if we don't have one yet, set up a memory dc for the plot */ 325 if (this->m_dcPlot == NULL) 326 { 327 this->m_dcPlot = CreateCompatibleDC(dc); 328 this->m_bitmapPlot = CreateCompatibleBitmap(dc, this->m_nClientWidth, this->m_nClientHeight); 329 this->m_bitmapOldPlot = (HBITMAP)SelectObject(this->m_dcPlot, this->m_bitmapPlot); 330 } 331 else if(bResize) 332 { 333 // the size of the drawing area has changed 334 // so create a new bitmap of the appropriate size 335 if(this->m_bitmapPlot != NULL) 336 { 337 this->m_bitmapPlot = (HBITMAP)SelectObject(this->m_dcPlot, this->m_bitmapOldPlot); 338 DeleteObject(this->m_bitmapPlot); 339 this->m_bitmapPlot = CreateCompatibleBitmap(dc, this->m_nClientWidth, this->m_nClientHeight); 340 SelectObject(this->m_dcPlot, this->m_bitmapPlot); 341 GraphCtrl_DrawPoint(this); 342 } 343 } 344 345 /* make sure the plot bitmap is cleared */ 346 SetBkColor(this->m_dcPlot, this->m_crBackColor); 347 FillRect(this->m_dcPlot, &this->m_rectClient, this->m_brushBack); 348 349 /* finally, force the plot area to redraw */ 350 InvalidateRect(this->m_hParentWnd, &this->m_rectClient, TRUE); 351 ReleaseDC(this->m_hParentWnd, dc); 352 } 353 354 double GraphCtrl_AppendPoint(TGraphCtrl* this, 355 double dNewPoint0, double dNewPoint1, 356 double dNewPoint2, double dNewPoint3) 357 { 358 /* append a data point to the plot & return the previous point */ 359 double dPrevious; 360 361 dPrevious = this->m_dCurrentPosition[0]; 362 this->m_dCurrentPosition[0] = dNewPoint0; 363 this->m_dCurrentPosition[1] = dNewPoint1; 364 this->m_dCurrentPosition[2] = dNewPoint2; 365 this->m_dCurrentPosition[3] = dNewPoint3; 366 GraphCtrl_ShiftGrid(this); 367 GraphCtrl_DrawPoint(this); 368 /* Invalidate(); */ 369 return dPrevious; 370 } 371 372 void GraphCtrl_Paint(TGraphCtrl* this, HWND hWnd, HDC dc) 373 { 374 HDC memDC; 375 HBITMAP memBitmap; 376 HBITMAP oldBitmap; /* bitmap originally found in CMemDC */ 377 378 /* RECT rcClient; */ 379 /* GetClientRect(hWnd, &rcClient); */ 380 /* FillSolidRect(dc, &rcClient, RGB(255, 0, 255)); */ 381 /* m_nClientWidth = rcClient.right - rcClient.left; */ 382 /* m_nClientHeight = rcClient.bottom - rcClient.top; */ 383 384 /* no real plotting work is performed here, */ 385 /* just putting the existing bitmaps on the client */ 386 387 /* to avoid flicker, establish a memory dc, draw to it */ 388 /* and then BitBlt it to the client */ 389 memDC = CreateCompatibleDC(dc); 390 memBitmap = (HBITMAP)CreateCompatibleBitmap(dc, this->m_nClientWidth, this->m_nClientHeight); 391 oldBitmap = (HBITMAP)SelectObject(memDC, memBitmap); 392 393 if (memDC != NULL) 394 { 395 /* first drop the grid on the memory dc */ 396 BitBlt(memDC, 0, 0, this->m_nClientWidth, this->m_nClientHeight, this->m_dcGrid, 0, 0, SRCCOPY); 397 /* now add the plot on top as a "pattern" via SRCPAINT. */ 398 /* works well with dark background and a light plot */ 399 BitBlt(memDC, 0, 0, this->m_nClientWidth, this->m_nClientHeight, this->m_dcPlot, 0, 0, SRCPAINT); /* SRCPAINT */ 400 /* finally send the result to the display */ 401 BitBlt(dc, 0, 0, this->m_nClientWidth, this->m_nClientHeight, memDC, 0, 0, SRCCOPY); 402 } 403 SelectObject(memDC, oldBitmap); 404 DeleteObject(memBitmap); 405 DeleteDC(memDC); 406 } 407 408 void GraphCtrl_ShiftGrid(TGraphCtrl* this) 409 { 410 RECT rectCleanUp; 411 HPEN oldPen, solidPen; 412 int i; 413 414 if (this->m_dcGrid == NULL) 415 return; 416 417 solidPen = CreatePen(PS_SOLID, 0, this->m_crGridColor); 418 419 /* Scroll the grid left: BitBlt it to itself */ 420 BitBlt(this->m_dcGrid, this->m_rectPlot.left, this->m_rectPlot.top + 1, 421 this->m_nPlotWidth, this->m_nPlotHeight, 422 this->m_dcGrid, this->m_rectPlot.left + this->m_nShiftPixels, this->m_rectPlot.top + 1, 423 SRCCOPY); 424 425 /* Set shift pixels */ 426 this->m_nGridOffsetPixels = (this->m_nGridOffsetPixels + this->m_nShiftPixels) % this->m_nGridXPixels; 427 428 /* Construct a rect in which needs update */ 429 rectCleanUp = this->m_rectPlot; 430 rectCleanUp.left = rectCleanUp.right - this->m_nShiftPixels; 431 432 /* Fill the cleanup area with the background */ 433 FillRect(this->m_dcGrid, &rectCleanUp, this->m_brushBack); 434 435 /* Draw the plot rectangle */ 436 oldPen = (HPEN)SelectObject(this->m_dcGrid, solidPen); 437 438 /* Redraw horizontal axis */ 439 for (i = rectCleanUp.top; i < rectCleanUp.bottom; i += this->m_nGridYPixels) 440 { 441 MoveToEx(this->m_dcGrid, rectCleanUp.left, i, NULL); 442 LineTo(this->m_dcGrid, rectCleanUp.right, i); 443 } 444 445 /* Redraw scrolled vertical axis */ 446 MoveToEx(this->m_dcGrid, rectCleanUp.right - this->m_nGridOffsetPixels, rectCleanUp.top, NULL); 447 LineTo(this->m_dcGrid, rectCleanUp.right - this->m_nGridOffsetPixels, rectCleanUp.bottom); 448 449 SelectObject(this->m_dcGrid, oldPen); 450 DeleteObject(solidPen); 451 } 452 453 void GraphCtrl_DrawPoint(TGraphCtrl* this) 454 { 455 /* this does the work of "scrolling" the plot to the left 456 * and appending a new data point all of the plotting is 457 * directed to the memory based bitmap associated with m_dcPlot 458 * the will subsequently be BitBlt'd to the client in Paint 459 */ 460 int currX, prevX, currY, prevY; 461 HPEN oldPen; 462 RECT rectCleanUp; 463 int i; 464 465 if (this->m_dcPlot != NULL) 466 { 467 /* shift the plot by BitBlt'ing it to itself 468 * note: the m_dcPlot covers the entire client 469 * but we only shift bitmap that is the size 470 * of the plot rectangle 471 * grab the right side of the plot (excluding m_nShiftPixels on the left) 472 * move this grabbed bitmap to the left by m_nShiftPixels 473 */ 474 BitBlt(this->m_dcPlot, this->m_rectPlot.left, this->m_rectPlot.top + 1, 475 this->m_nPlotWidth, this->m_nPlotHeight, this->m_dcPlot, 476 this->m_rectPlot.left+this->m_nShiftPixels, this->m_rectPlot.top + 1, 477 SRCCOPY); 478 479 /* establish a rectangle over the right side of plot */ 480 /* which now needs to be cleaned up prior to adding the new point */ 481 rectCleanUp = this->m_rectPlot; 482 rectCleanUp.left = rectCleanUp.right - this->m_nShiftPixels; 483 484 /* fill the cleanup area with the background */ 485 FillRect(this->m_dcPlot, &rectCleanUp, this->m_brushBack); 486 487 /* draw the next line segment */ 488 for (i = 0; i < MAX_PLOTS; i++) 489 { 490 /* grab the plotting pen */ 491 oldPen = (HPEN)SelectObject(this->m_dcPlot, this->m_penPlot[i]); 492 493 /* move to the previous point */ 494 prevX = this->m_rectPlot.right-this->m_nPlotShiftPixels; 495 prevY = this->m_rectPlot.bottom - 496 (long)((this->m_dPreviousPosition[i] - this->m_dLowerLimit) * this->m_dVerticalFactor); 497 MoveToEx(this->m_dcPlot, prevX, prevY, NULL); 498 499 /* draw to the current point */ 500 currX = this->m_rectPlot.right-this->m_nHalfShiftPixels; 501 currY = this->m_rectPlot.bottom - 502 (long)((this->m_dCurrentPosition[i] - this->m_dLowerLimit) * this->m_dVerticalFactor); 503 LineTo(this->m_dcPlot, currX, currY); 504 505 /* Restore the pen */ 506 SelectObject(this->m_dcPlot, oldPen); 507 508 /* if the data leaks over the upper or lower plot boundaries 509 * fill the upper and lower leakage with the background 510 * this will facilitate clipping on an as needed basis 511 * as opposed to always calling IntersectClipRect 512 */ 513 if ((prevY <= this->m_rectPlot.top) || (currY <= this->m_rectPlot.top)) 514 { 515 RECT rc; 516 rc.bottom = this->m_rectPlot.top + 1; 517 rc.left = prevX; 518 rc.right = currX + 1; 519 rc.top = this->m_rectClient.top; 520 FillRect(this->m_dcPlot, &rc, this->m_brushBack); 521 } 522 if ((prevY >= this->m_rectPlot.bottom) || (currY >= this->m_rectPlot.bottom)) 523 { 524 RECT rc; 525 rc.bottom = this->m_rectClient.bottom + 1; 526 rc.left = prevX; 527 rc.right = currX + 1; 528 rc.top = this->m_rectPlot.bottom + 1; 529 /* RECT rc(prevX, m_rectPlot.bottom+1, currX+1, m_rectClient.bottom+1); */ 530 FillRect(this->m_dcPlot, &rc, this->m_brushBack); 531 } 532 533 /* store the current point for connection to the next point */ 534 this->m_dPreviousPosition[i] = this->m_dCurrentPosition[i]; 535 } 536 } 537 } 538 539 void GraphCtrl_Resize(TGraphCtrl* this) 540 { 541 /* NOTE: Resize automatically gets called during the setup of the control */ 542 GetClientRect(this->m_hWnd, &this->m_rectClient); 543 544 /* set some member variables to avoid multiple function calls */ 545 this->m_nClientHeight = this->m_rectClient.bottom - this->m_rectClient.top;/* m_rectClient.Height(); */ 546 this->m_nClientWidth = this->m_rectClient.right - this->m_rectClient.left;/* m_rectClient.Width(); */ 547 548 /* the "left" coordinate and "width" will be modified in */ 549 /* InvalidateCtrl to be based on the width of the y axis scaling */ 550 #if 0 551 this->m_rectPlot.left = 20; 552 this->m_rectPlot.top = 10; 553 this->m_rectPlot.right = this->m_rectClient.right-10; 554 this->m_rectPlot.bottom = this->m_rectClient.bottom-25; 555 #else 556 this->m_rectPlot.left = 0; 557 this->m_rectPlot.top = -1; 558 this->m_rectPlot.right = this->m_rectClient.right; 559 this->m_rectPlot.bottom = this->m_rectClient.bottom; 560 #endif 561 562 /* set some member variables to avoid multiple function calls */ 563 this->m_nPlotHeight = this->m_rectPlot.bottom - this->m_rectPlot.top;/* m_rectPlot.Height(); */ 564 this->m_nPlotWidth = this->m_rectPlot.right - this->m_rectPlot.left;/* m_rectPlot.Width(); */ 565 566 /* set the scaling factor for now, this can be adjusted */ 567 /* in the SetRange functions */ 568 this->m_dVerticalFactor = (double)this->m_nPlotHeight / this->m_dRange; 569 } 570 571 #if 0 572 void TGraphCtrl::Reset() 573 { 574 /* to clear the existing data (in the form of a bitmap) */ 575 /* simply invalidate the entire control */ 576 InvalidateCtrl(); 577 } 578 #endif 579 580 extern TGraphCtrl PerformancePageCpuUsageHistoryGraph; 581 extern TGraphCtrl PerformancePageMemUsageHistoryGraph; 582 extern HWND hPerformancePageCpuUsageHistoryGraph; 583 extern HWND hPerformancePageMemUsageHistoryGraph; 584 585 INT_PTR CALLBACK 586 GraphCtrl_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 587 { 588 RECT rcClient; 589 HDC hdc; 590 PAINTSTRUCT ps; 591 592 switch (message) 593 { 594 case WM_ERASEBKGND: 595 return TRUE; 596 /* 597 * Filter out mouse & keyboard messages 598 */ 599 /* case WM_APPCOMMAND: */ 600 case WM_CAPTURECHANGED: 601 case WM_LBUTTONDBLCLK: 602 case WM_LBUTTONDOWN: 603 case WM_LBUTTONUP: 604 case WM_MBUTTONDBLCLK: 605 case WM_MBUTTONDOWN: 606 case WM_MBUTTONUP: 607 case WM_MOUSEACTIVATE: 608 case WM_MOUSEHOVER: 609 case WM_MOUSELEAVE: 610 case WM_MOUSEMOVE: 611 /* case WM_MOUSEWHEEL: */ 612 case WM_NCHITTEST: 613 case WM_NCLBUTTONDBLCLK: 614 case WM_NCLBUTTONDOWN: 615 case WM_NCLBUTTONUP: 616 case WM_NCMBUTTONDBLCLK: 617 case WM_NCMBUTTONDOWN: 618 case WM_NCMBUTTONUP: 619 /* case WM_NCMOUSEHOVER: */ 620 /* case WM_NCMOUSELEAVE: */ 621 case WM_NCMOUSEMOVE: 622 case WM_NCRBUTTONDBLCLK: 623 case WM_NCRBUTTONDOWN: 624 case WM_NCRBUTTONUP: 625 /* case WM_NCXBUTTONDBLCLK: */ 626 /* case WM_NCXBUTTONDOWN: */ 627 /* case WM_NCXBUTTONUP: */ 628 case WM_RBUTTONDBLCLK: 629 case WM_RBUTTONDOWN: 630 case WM_RBUTTONUP: 631 /* case WM_XBUTTONDBLCLK: */ 632 /* case WM_XBUTTONDOWN: */ 633 /* case WM_XBUTTONUP: */ 634 case WM_ACTIVATE: 635 case WM_CHAR: 636 case WM_DEADCHAR: 637 case WM_GETHOTKEY: 638 case WM_HOTKEY: 639 case WM_KEYDOWN: 640 case WM_KEYUP: 641 case WM_KILLFOCUS: 642 case WM_SETFOCUS: 643 case WM_SETHOTKEY: 644 case WM_SYSCHAR: 645 case WM_SYSDEADCHAR: 646 case WM_SYSKEYDOWN: 647 case WM_SYSKEYUP: 648 return 0; 649 650 case WM_NCCALCSIZE: 651 return 0; 652 653 case WM_SIZE: 654 if (hWnd == hPerformancePageMemUsageHistoryGraph) 655 { 656 GraphCtrl_Resize(&PerformancePageMemUsageHistoryGraph); 657 GraphCtrl_InvalidateCtrl(&PerformancePageMemUsageHistoryGraph, TRUE); 658 } 659 if (hWnd == hPerformancePageCpuUsageHistoryGraph) 660 { 661 GraphCtrl_Resize(&PerformancePageCpuUsageHistoryGraph); 662 GraphCtrl_InvalidateCtrl(&PerformancePageCpuUsageHistoryGraph, TRUE); 663 } 664 return 0; 665 666 case WM_PAINT: 667 hdc = BeginPaint(hWnd, &ps); 668 GetClientRect(hWnd, &rcClient); 669 if (hWnd == hPerformancePageMemUsageHistoryGraph) 670 GraphCtrl_Paint(&PerformancePageMemUsageHistoryGraph, hWnd, hdc); 671 if (hWnd == hPerformancePageCpuUsageHistoryGraph) 672 GraphCtrl_Paint(&PerformancePageCpuUsageHistoryGraph, hWnd, hdc); 673 EndPaint(hWnd, &ps); 674 return 0; 675 } 676 677 /* 678 * We pass on all non-handled messages 679 */ 680 return CallWindowProcW(OldGraphCtrlWndProc, hWnd, message, wParam, lParam); 681 } 682