1 /*
2  * PROJECT:     ReactOS Task Manager
3  * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-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  *              Copyright 2021 Valerij Zaporogeci <vlrzprgts@gmail.com>
8  */
9 
10 #include "precomp.h"
11 
12 #include <math.h>
13 
14 WNDPROC OldGraphCtrlWndProc;
15 
16 BOOL
GraphCtrl_Create(PTM_GRAPH_CONTROL inst,HWND hWnd,HWND hParentWnd,PTM_FORMAT fmt)17 GraphCtrl_Create(PTM_GRAPH_CONTROL inst, HWND hWnd, HWND hParentWnd, PTM_FORMAT fmt)
18 {
19     HDC     hdc, hdcg;
20     HBITMAP hbmOld;
21     UINT    Size;
22     INT     p;
23     RECT    rc;
24 
25     inst->hParentWnd = hParentWnd;
26     inst->hWnd = hWnd;
27 
28     Size = GetSystemMetrics(SM_CXSCREEN);
29     inst->BitmapWidth = Size;
30     Size /= PLOT_SHIFT;
31     inst->PointBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Size * NUM_PLOTS);
32     if (!inst->PointBuffer)
33     {
34         goto fail;
35     }
36 
37     inst->NumberOfPoints = Size;
38     inst->CurrIndex = 0;
39 
40     /* Styling */
41     inst->hPenGrid = CreatePen(PS_SOLID, 0, fmt->clrGrid);
42     inst->hPen0 = CreatePen(PS_SOLID, 0, fmt->clrPlot0);
43     inst->hPen1 = CreatePen(PS_SOLID, 0, fmt->clrPlot1);
44     inst->hBrushBack = CreateSolidBrush(fmt->clrBack);
45 
46     if (!inst->hPenGrid ||
47         !inst->hPen0 ||
48         !inst->hPen1 ||
49         !inst->hBrushBack)
50     {
51         goto fail;
52     }
53 
54     if (fmt->GridCellWidth >= PLOT_SHIFT << 2)
55         inst->GridCellWidth = fmt->GridCellWidth;
56     else
57         inst->GridCellWidth = PLOT_SHIFT << 2;
58     if (fmt->GridCellHeight >= PLOT_SHIFT << 2)
59         inst->GridCellHeight = fmt->GridCellHeight;
60     else
61         inst->GridCellHeight = PLOT_SHIFT << 2;
62 
63     inst->DrawSecondaryPlot = fmt->DrawSecondaryPlot;
64 
65     GetClientRect(hWnd, &rc);
66     inst->BitmapHeight = rc.bottom;
67     inst->ftPixelsPerPercent = (FLOAT)(inst->BitmapHeight) / 100.00f;
68 
69     hdc = GetDC(hParentWnd);
70     hdcg = CreateCompatibleDC(hdc);
71     inst->hdcGraph = hdcg;
72     inst->hbmGraph = CreateCompatibleBitmap(hdc, inst->BitmapWidth, inst->BitmapHeight);
73 
74     if (!hdc ||
75         !hdcg ||
76         !inst->hbmGraph)
77     {
78         goto fail;
79     }
80 
81     ReleaseDC(hParentWnd, hdc);
82     hbmOld = (HBITMAP)SelectObject(hdcg, inst->hbmGraph);
83     DeleteObject(hbmOld);
84 
85     SetBkColor(hdcg, fmt->clrBack);
86     rc.right = inst->BitmapWidth;
87     FillRect(hdcg, &rc, inst->hBrushBack);
88 
89     inst->CurrShift = 0;
90     SelectObject(hdcg, inst->hPenGrid);
91     for (p = inst->GridCellHeight - 1;
92          p < inst->BitmapHeight;
93          p += inst->GridCellHeight)
94     {
95         MoveToEx(hdcg, 0, p, NULL);
96         LineTo(hdcg, inst->BitmapWidth, p);
97     }
98     for (p = inst->BitmapWidth - 1;
99          p > 0;
100          p -= inst->GridCellWidth)
101     {
102         MoveToEx(hdcg, p, 0, NULL);
103         LineTo(hdcg, p, inst->BitmapHeight);
104     }
105     SelectObject(hdcg, inst->hPen0);
106 
107     return TRUE;
108 
109 fail:
110     GraphCtrl_Dispose(inst);
111     return FALSE;
112 }
113 
114 void
GraphCtrl_Dispose(PTM_GRAPH_CONTROL inst)115 GraphCtrl_Dispose(PTM_GRAPH_CONTROL inst)
116 {
117     if (inst->PointBuffer)
118         HeapFree(GetProcessHeap(), 0, inst->PointBuffer);
119 
120     if (inst->hdcGraph)
121         DeleteDC(inst->hdcGraph);
122 
123     if (inst->hPenGrid)
124         DeleteObject(inst->hPenGrid);
125 
126     if (inst->hPen0)
127         DeleteObject(inst->hPen0);
128 
129     if (inst->hPen1)
130         DeleteObject(inst->hPen1);
131 
132     if (inst->hBrushBack)
133         DeleteObject(inst->hBrushBack);
134 
135     if (inst->hbmGraph)
136         DeleteObject(inst->hbmGraph);
137 }
138 
139 void
GraphCtrl_AddPoint(PTM_GRAPH_CONTROL inst,BYTE val0,BYTE val1)140 GraphCtrl_AddPoint(PTM_GRAPH_CONTROL inst, BYTE val0, BYTE val1)
141 {
142     HDC    hdcg;
143     PBYTE  t;
144     RECT   rcDirt;
145 
146     UINT   Prev0, Prev1, RetainingWidth;
147     INT    PrevY, CurrY, p, v;
148 
149     hdcg = inst->hdcGraph;
150     RetainingWidth = inst->BitmapWidth - PLOT_SHIFT;
151     t = inst->PointBuffer;
152     Prev0 = *(t + inst->CurrIndex);
153     Prev1 = *(t + inst->CurrIndex + inst->NumberOfPoints);
154     if (inst->CurrIndex < inst->NumberOfPoints - 1)
155     {
156         inst->CurrIndex++;
157     }
158     else
159     {
160         inst->CurrIndex = 0;
161     }
162     *(t + inst->CurrIndex) = val0;
163     *(t + inst->CurrIndex + inst->NumberOfPoints) = val1;
164 
165     /* Drawing points, first shifting the plot left */
166     BitBlt(hdcg, 0, 0, RetainingWidth, inst->BitmapHeight, hdcg, PLOT_SHIFT, 0, SRCCOPY);
167 
168     rcDirt.left = RetainingWidth;
169     rcDirt.top = 0;
170     rcDirt.right = inst->BitmapWidth;
171     rcDirt.bottom = inst->BitmapHeight;
172     FillRect(hdcg, &rcDirt, inst->hBrushBack);
173 
174     SelectObject(hdcg, inst->hPenGrid);
175     for (p = inst->GridCellHeight - 1;
176          p < inst->BitmapHeight;
177          p += inst->GridCellHeight)
178     {
179         MoveToEx(hdcg, RetainingWidth, p, NULL);
180         LineTo(hdcg, inst->BitmapWidth, p);
181     }
182     v = inst->CurrShift + PLOT_SHIFT;
183     if (v >= inst->GridCellWidth)
184     {
185         v -= inst->GridCellWidth;
186         p = inst->BitmapWidth - v - 1;
187         MoveToEx(hdcg, p, 0, NULL);
188         LineTo(hdcg, p, inst->BitmapHeight);
189     }
190     inst->CurrShift = v;
191 
192     if (inst->DrawSecondaryPlot)
193     {
194         SelectObject(inst->hdcGraph, inst->hPen1);
195 
196         PrevY = inst->BitmapHeight - Prev1 * inst->ftPixelsPerPercent;
197         MoveToEx(inst->hdcGraph, RetainingWidth - 1, PrevY, NULL);
198         CurrY = inst->BitmapHeight - val1 * inst->ftPixelsPerPercent;
199         LineTo(inst->hdcGraph, inst->BitmapWidth - 1, CurrY);
200     }
201 
202     SelectObject(inst->hdcGraph, inst->hPen0);
203     PrevY = inst->BitmapHeight - Prev0 * inst->ftPixelsPerPercent;
204     MoveToEx(inst->hdcGraph, RetainingWidth - 1, PrevY, NULL);
205     CurrY = inst->BitmapHeight - val0 * inst->ftPixelsPerPercent;
206     LineTo(inst->hdcGraph, inst->BitmapWidth - 1, CurrY);
207 }
208 
209 inline void
GraphCtrl_RedrawBitmap(PTM_GRAPH_CONTROL inst,INT h)210 GraphCtrl_RedrawBitmap(PTM_GRAPH_CONTROL inst, INT h)
211 {
212     HDC    hdcg;
213     PBYTE  t;
214     RECT   rc;
215     INT    i, j, y, x, p;
216     FLOAT  coef;
217 
218     hdcg = inst->hdcGraph;
219     rc.left = 0; rc.top = 0;
220     rc.right = inst->BitmapWidth; rc.bottom = h;
221     FillRect(hdcg, &rc, inst->hBrushBack);
222 
223     SelectObject(hdcg, inst->hPenGrid);
224 
225     for (p = inst->GridCellHeight - 1;
226          p < inst->BitmapHeight;
227          p += inst->GridCellHeight)
228     {
229         MoveToEx(hdcg, 0, p, NULL);
230         LineTo(hdcg, inst->BitmapWidth, p);
231     }
232 
233     for (p = inst->BitmapWidth - inst->CurrShift - 1;
234          p > 0;
235          p -= inst->GridCellWidth)
236     {
237         MoveToEx(hdcg, p, 0, NULL);
238         LineTo(hdcg, p, inst->BitmapHeight);
239     }
240 
241     coef = inst->ftPixelsPerPercent;
242 
243     if (inst->DrawSecondaryPlot)
244     {
245         SelectObject(hdcg, inst->hPen1);
246         t = inst->PointBuffer + inst->NumberOfPoints;
247         x = inst->BitmapWidth - 1;
248         j = inst->CurrIndex;
249         y = h - *(t + j) * coef;
250         MoveToEx(hdcg, x, y, NULL);
251         for (i = 0; i < inst->NumberOfPoints; i++)
252         {
253             j = (j ? j : inst->NumberOfPoints) - 1;
254             y = h - *(t + j) * coef;
255             x -= PLOT_SHIFT;
256             LineTo(hdcg, x, y);
257         }
258     }
259 
260     SelectObject(hdcg, inst->hPen0);
261     t = inst->PointBuffer;
262     x = inst->BitmapWidth - 1;
263     j = inst->CurrIndex;
264     y = h - *(t + j) * coef;
265     MoveToEx(hdcg, x, y, NULL);
266 
267     for (i = 0; i < inst->NumberOfPoints; i++)
268     {
269         j = (j ? j : inst->NumberOfPoints) - 1;
270         y = h - *(t + j) * coef;
271         x -= PLOT_SHIFT;
272         LineTo(hdcg, x, y);
273     }
274 }
275 
276 inline void
GraphCtrl_RedrawOnHeightChange(PTM_GRAPH_CONTROL inst,INT nh)277 GraphCtrl_RedrawOnHeightChange(PTM_GRAPH_CONTROL inst, INT nh)
278 {
279     HDC     hdc;
280     HBITMAP hbmOld;
281 
282     inst->BitmapHeight = nh;
283     inst->ftPixelsPerPercent = (FLOAT)nh / 100.00f;
284 
285     hdc = GetDC(inst->hParentWnd);
286     hbmOld = inst->hbmGraph;
287     inst->hbmGraph = CreateCompatibleBitmap(hdc, inst->BitmapWidth, nh);
288     SelectObject(inst->hdcGraph, inst->hbmGraph);
289     DeleteObject(hbmOld);
290     ReleaseDC(inst->hParentWnd, hdc);
291 
292     GraphCtrl_RedrawBitmap(inst, nh);
293 }
294 
295 extern TM_GRAPH_CONTROL PerformancePageCpuUsageHistoryGraph;
296 extern TM_GRAPH_CONTROL PerformancePageMemUsageHistoryGraph;
297 extern HWND hPerformancePageCpuUsageHistoryGraph;
298 extern HWND hPerformancePageMemUsageHistoryGraph;
299 
300 INT_PTR CALLBACK
GraphCtrl_WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)301 GraphCtrl_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
302 {
303     PTM_GRAPH_CONTROL graph;
304 
305     switch (message)
306     {
307         case WM_ERASEBKGND:
308             return TRUE;
309         /*
310          *  Filter out mouse  & keyboard messages
311          */
312         // case WM_APPCOMMAND:
313         case WM_CAPTURECHANGED:
314         case WM_LBUTTONDBLCLK:
315         case WM_LBUTTONDOWN:
316         case WM_LBUTTONUP:
317         case WM_MBUTTONDBLCLK:
318         case WM_MBUTTONDOWN:
319         case WM_MBUTTONUP:
320         case WM_MOUSEACTIVATE:
321         case WM_MOUSEHOVER:
322         case WM_MOUSELEAVE:
323         case WM_MOUSEMOVE:
324         // case WM_MOUSEWHEEL:
325         case WM_NCHITTEST:
326         case WM_NCLBUTTONDBLCLK:
327         case WM_NCLBUTTONDOWN:
328         case WM_NCLBUTTONUP:
329         case WM_NCMBUTTONDBLCLK:
330         case WM_NCMBUTTONDOWN:
331         case WM_NCMBUTTONUP:
332         // case WM_NCMOUSEHOVER:
333         // case WM_NCMOUSELEAVE:
334         case WM_NCMOUSEMOVE:
335         case WM_NCRBUTTONDBLCLK:
336         case WM_NCRBUTTONDOWN:
337         case WM_NCRBUTTONUP:
338         // case WM_NCXBUTTONDBLCLK:
339         // case WM_NCXBUTTONDOWN:
340         // case WM_NCXBUTTONUP:
341         case WM_RBUTTONDBLCLK:
342         case WM_RBUTTONDOWN:
343         case WM_RBUTTONUP:
344         // case WM_XBUTTONDBLCLK:
345         // case WM_XBUTTONDOWN:
346         // case WM_XBUTTONUP:
347         case WM_ACTIVATE:
348         case WM_CHAR:
349         case WM_DEADCHAR:
350         case WM_GETHOTKEY:
351         case WM_HOTKEY:
352         case WM_KEYDOWN:
353         case WM_KEYUP:
354         case WM_KILLFOCUS:
355         case WM_SETFOCUS:
356         case WM_SETHOTKEY:
357         case WM_SYSCHAR:
358         case WM_SYSDEADCHAR:
359         case WM_SYSKEYDOWN:
360         case WM_SYSKEYUP:
361             return 0;
362 
363         case WM_NCCALCSIZE:
364             return 0;
365 
366         case WM_SIZE:
367         {
368             if (hWnd == hPerformancePageCpuUsageHistoryGraph)
369                 graph = &PerformancePageCpuUsageHistoryGraph;
370             else if (hWnd == hPerformancePageMemUsageHistoryGraph)
371                 graph = &PerformancePageMemUsageHistoryGraph;
372             else
373                 return 0;
374 
375             if (HIWORD(lParam) != graph->BitmapHeight)
376             {
377                 GraphCtrl_RedrawOnHeightChange(graph, HIWORD(lParam));
378             }
379             InvalidateRect(hWnd, NULL, FALSE);
380 
381             return 0;
382         }
383 
384         case WM_PAINT:
385         {
386             RECT        rcClient;
387             HDC         hdc;
388             PAINTSTRUCT ps;
389 
390             if (hWnd == hPerformancePageCpuUsageHistoryGraph)
391                 graph = &PerformancePageCpuUsageHistoryGraph;
392             else if (hWnd == hPerformancePageMemUsageHistoryGraph)
393                 graph = &PerformancePageMemUsageHistoryGraph;
394             else
395                 return 0;
396 
397             hdc = BeginPaint(hWnd, &ps);
398             GetClientRect(hWnd, &rcClient);
399             BitBlt(hdc, 0, 0,
400                    rcClient.right,
401                    rcClient.bottom,
402                    graph->hdcGraph,
403                    graph->BitmapWidth - rcClient.right,
404                    0,
405                    SRCCOPY);
406             EndPaint(hWnd, &ps);
407             return 0;
408         }
409     }
410 
411     /*
412      *  We pass on all non-handled messages
413      */
414     return CallWindowProcW(OldGraphCtrlWndProc, hWnd, message, wParam, lParam);
415 }
416