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