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