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