Panda3D
|
00001 // Filename: winStatsGraph.cxx 00002 // Created by: drose (03Dec03) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "winStatsGraph.h" 00016 #include "winStatsMonitor.h" 00017 #include "winStatsLabelStack.h" 00018 00019 bool WinStatsGraph::_graph_window_class_registered = false; 00020 const char * const WinStatsGraph::_graph_window_class_name = "graph"; 00021 00022 DWORD WinStatsGraph::graph_window_style = 00023 WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_OVERLAPPEDWINDOW | WS_VISIBLE; 00024 00025 //////////////////////////////////////////////////////////////////// 00026 // Function: WinStatsGraph::Constructor 00027 // Access: Public 00028 // Description: 00029 //////////////////////////////////////////////////////////////////// 00030 WinStatsGraph:: 00031 WinStatsGraph(WinStatsMonitor *monitor) : 00032 _monitor(monitor) 00033 { 00034 _window = 0; 00035 _graph_window = 0; 00036 _sizewe_cursor = LoadCursor(NULL, IDC_SIZEWE); 00037 _hand_cursor = LoadCursor(NULL, IDC_HAND); 00038 _bitmap = 0; 00039 _bitmap_dc = 0; 00040 00041 _graph_left = 0; 00042 _graph_top = 0; 00043 _bitmap_xsize = 0; 00044 _bitmap_ysize = 0; 00045 00046 _dark_color = RGB(51, 51, 51); 00047 _light_color = RGB(154, 154, 154); 00048 _user_guide_bar_color = RGB(130, 150, 255); 00049 _dark_pen = CreatePen(PS_SOLID, 1, _dark_color); 00050 _light_pen = CreatePen(PS_SOLID, 1, _light_color); 00051 _user_guide_bar_pen = CreatePen(PS_DASH, 1, _user_guide_bar_color); 00052 00053 _drag_mode = DM_none; 00054 _potential_drag_mode = DM_none; 00055 _drag_scale_start = 0.0f; 00056 00057 _pause = false; 00058 } 00059 00060 //////////////////////////////////////////////////////////////////// 00061 // Function: WinStatsGraph::Destructor 00062 // Access: Public, Virtual 00063 // Description: 00064 //////////////////////////////////////////////////////////////////// 00065 WinStatsGraph:: 00066 ~WinStatsGraph() { 00067 _monitor = (WinStatsMonitor *)NULL; 00068 release_bitmap(); 00069 00070 DeleteObject(_dark_pen); 00071 DeleteObject(_light_pen); 00072 DeleteObject(_user_guide_bar_pen); 00073 00074 Brushes::iterator bi; 00075 for (bi = _brushes.begin(); bi != _brushes.end(); ++bi) { 00076 HBRUSH brush = (*bi).second; 00077 DeleteObject(brush); 00078 } 00079 00080 if (_graph_window) { 00081 DestroyWindow(_graph_window); 00082 _graph_window = 0; 00083 } 00084 00085 if (_window) { 00086 DestroyWindow(_window); 00087 _window = 0; 00088 } 00089 } 00090 00091 //////////////////////////////////////////////////////////////////// 00092 // Function: WinStatsGraph::new_collector 00093 // Access: Public, Virtual 00094 // Description: Called whenever a new Collector definition is 00095 // received from the client. 00096 //////////////////////////////////////////////////////////////////// 00097 void WinStatsGraph:: 00098 new_collector(int new_collector) { 00099 } 00100 00101 //////////////////////////////////////////////////////////////////// 00102 // Function: WinStatsGraph::new_data 00103 // Access: Public, Virtual 00104 // Description: Called whenever new data arrives. 00105 //////////////////////////////////////////////////////////////////// 00106 void WinStatsGraph:: 00107 new_data(int thread_index, int frame_number) { 00108 } 00109 00110 //////////////////////////////////////////////////////////////////// 00111 // Function: WinStatsGraph::force_redraw 00112 // Access: Public, Virtual 00113 // Description: Called when it is necessary to redraw the entire graph. 00114 //////////////////////////////////////////////////////////////////// 00115 void WinStatsGraph:: 00116 force_redraw() { 00117 } 00118 00119 //////////////////////////////////////////////////////////////////// 00120 // Function: WinStatsGraph::changed_graph_size 00121 // Access: Public, Virtual 00122 // Description: Called when the user has resized the window, forcing 00123 // a resize of the graph. 00124 //////////////////////////////////////////////////////////////////// 00125 void WinStatsGraph:: 00126 changed_graph_size(int graph_xsize, int graph_ysize) { 00127 } 00128 00129 //////////////////////////////////////////////////////////////////// 00130 // Function: WinStatsGraph::set_time_units 00131 // Access: Public, Virtual 00132 // Description: Called when the user selects a new time units from 00133 // the monitor pulldown menu, this should adjust the 00134 // units for the graph to the indicated mask if it is a 00135 // time-based graph. 00136 //////////////////////////////////////////////////////////////////// 00137 void WinStatsGraph:: 00138 set_time_units(int unit_mask) { 00139 } 00140 00141 //////////////////////////////////////////////////////////////////// 00142 // Function: WinStatsGraph::set_scroll_speed 00143 // Access: Public 00144 // Description: Called when the user selects a new scroll speed from 00145 // the monitor pulldown menu, this should adjust the 00146 // speed for the graph to the indicated value. 00147 //////////////////////////////////////////////////////////////////// 00148 void WinStatsGraph:: 00149 set_scroll_speed(double scroll_speed) { 00150 } 00151 00152 //////////////////////////////////////////////////////////////////// 00153 // Function: WinStatsGraph::set_pause 00154 // Access: Public 00155 // Description: Changes the pause flag for the graph. When this flag 00156 // is true, the graph does not update in response to new 00157 // data. 00158 //////////////////////////////////////////////////////////////////// 00159 void WinStatsGraph:: 00160 set_pause(bool pause) { 00161 _pause = pause; 00162 } 00163 00164 //////////////////////////////////////////////////////////////////// 00165 // Function: WinStatsGraph::user_guide_bars_changed 00166 // Access: Public 00167 // Description: Called when the user guide bars have been changed. 00168 //////////////////////////////////////////////////////////////////// 00169 void WinStatsGraph:: 00170 user_guide_bars_changed() { 00171 InvalidateRect(_window, NULL, TRUE); 00172 InvalidateRect(_graph_window, NULL, TRUE); 00173 } 00174 00175 //////////////////////////////////////////////////////////////////// 00176 // Function: WinStatsGraph::clicked_label 00177 // Access: Public, Virtual 00178 // Description: Called when the user single-clicks on a label. 00179 //////////////////////////////////////////////////////////////////// 00180 void WinStatsGraph:: 00181 clicked_label(int collector_index) { 00182 } 00183 00184 //////////////////////////////////////////////////////////////////// 00185 // Function: WinStatsGraph::close 00186 // Access: Protected 00187 // Description: Should be called when the user closes the associated 00188 // window. This tells the monitor to remove the graph. 00189 //////////////////////////////////////////////////////////////////// 00190 void WinStatsGraph:: 00191 close() { 00192 WinStatsMonitor *monitor = _monitor; 00193 _monitor = (WinStatsMonitor *)NULL; 00194 if (monitor != (WinStatsMonitor *)NULL) { 00195 monitor->remove_graph(this); 00196 } 00197 } 00198 00199 //////////////////////////////////////////////////////////////////// 00200 // Function: WinStatsGraph::setup_label_stack 00201 // Access: Protected 00202 // Description: Sets up the label stack on the left edge of the 00203 // frame. 00204 //////////////////////////////////////////////////////////////////// 00205 void WinStatsGraph:: 00206 setup_label_stack() { 00207 _label_stack.setup(_window); 00208 move_label_stack(); 00209 } 00210 00211 //////////////////////////////////////////////////////////////////// 00212 // Function: WinStatsGraph::move_label_stack 00213 // Access: Protected 00214 // Description: Repositions the label stack if its coordinates or 00215 // size have changed. 00216 //////////////////////////////////////////////////////////////////// 00217 void WinStatsGraph:: 00218 move_label_stack() { 00219 if (_label_stack.is_setup()) { 00220 RECT rect; 00221 GetClientRect(_window, &rect); 00222 00223 rect.left += 8; 00224 rect.right = _left_margin - 8; 00225 rect.bottom -= _bottom_margin; 00226 00227 _label_stack.set_pos(rect.left, rect.top, 00228 rect.right - rect.left, rect.bottom - rect.top); 00229 } 00230 } 00231 00232 //////////////////////////////////////////////////////////////////// 00233 // Function: WinStatsGraph::get_collector_brush 00234 // Access: Protected 00235 // Description: Returns a brush suitable for drawing in the indicated 00236 // collector's color. 00237 //////////////////////////////////////////////////////////////////// 00238 HBRUSH WinStatsGraph:: 00239 get_collector_brush(int collector_index) { 00240 Brushes::iterator bi; 00241 bi = _brushes.find(collector_index); 00242 if (bi != _brushes.end()) { 00243 return (*bi).second; 00244 } 00245 00246 // Ask the monitor what color this guy should be. 00247 LRGBColor rgb = _monitor->get_collector_color(collector_index); 00248 int r = (int)(rgb[0] * 255.0f); 00249 int g = (int)(rgb[1] * 255.0f); 00250 int b = (int)(rgb[2] * 255.0f); 00251 HBRUSH brush = CreateSolidBrush(RGB(r, g, b)); 00252 00253 _brushes[collector_index] = brush; 00254 return brush; 00255 } 00256 00257 //////////////////////////////////////////////////////////////////// 00258 // Function: WinStatsGraph::window_proc 00259 // Access: Protected 00260 // Description: This window_proc should be called up to by the 00261 // derived classes for any messages that are not 00262 // specifically handled by the derived class. 00263 //////////////////////////////////////////////////////////////////// 00264 LONG WinStatsGraph:: 00265 window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { 00266 switch (msg) { 00267 case WM_DESTROY: 00268 close(); 00269 break; 00270 00271 case WM_SIZE: 00272 move_label_stack(); 00273 InvalidateRect(hwnd, NULL, TRUE); 00274 break; 00275 00276 case WM_SIZING: 00277 set_drag_mode(DM_sizing); 00278 break; 00279 00280 case WM_EXITSIZEMOVE: 00281 set_drag_mode(DM_none); 00282 break; 00283 00284 case WM_SETCURSOR: 00285 { 00286 // Why is it so hard to ask for the cursor position within the 00287 // window's client area? 00288 POINT point; 00289 GetCursorPos(&point); 00290 WINDOWINFO winfo; 00291 GetWindowInfo(hwnd, &winfo); 00292 const RECT &rect = winfo.rcClient; 00293 int x = point.x - rect.left; 00294 int y = point.y - rect.top; 00295 int width = rect.right - rect.left; 00296 int height = rect.bottom - rect.top; 00297 00298 _potential_drag_mode = consider_drag_start(x, y, width, height); 00299 00300 switch (_potential_drag_mode) { 00301 case DM_left_margin: 00302 case DM_right_margin: 00303 SetCursor(_sizewe_cursor); 00304 return TRUE; 00305 00306 case DM_guide_bar: 00307 SetCursor(_hand_cursor); 00308 return TRUE; 00309 00310 default: 00311 case DM_none: 00312 break; 00313 } 00314 } 00315 break; 00316 00317 case WM_LBUTTONDOWN: 00318 if (_potential_drag_mode != DM_none) { 00319 set_drag_mode(_potential_drag_mode); 00320 _drag_start_x = (PN_int16)LOWORD(lparam); 00321 _drag_start_y = (PN_int16)HIWORD(lparam); 00322 SetCapture(_window); 00323 } 00324 return 0; 00325 00326 case WM_MOUSEMOVE: 00327 if (_drag_mode == DM_left_margin) { 00328 PN_int16 x = LOWORD(lparam); 00329 _left_margin += (x - _drag_start_x); 00330 _drag_start_x = x; 00331 InvalidateRect(hwnd, NULL, TRUE); 00332 move_label_stack(); 00333 return 0; 00334 00335 } else if (_drag_mode == DM_right_margin) { 00336 PN_int16 x = LOWORD(lparam); 00337 _right_margin += (_drag_start_x - x); 00338 _drag_start_x = x; 00339 InvalidateRect(hwnd, NULL, TRUE); 00340 return 0; 00341 } 00342 break; 00343 00344 case WM_LBUTTONUP: 00345 set_drag_mode(DM_none); 00346 ReleaseCapture(); 00347 break; 00348 00349 case WM_PAINT: 00350 { 00351 PAINTSTRUCT ps; 00352 HDC hdc = BeginPaint(hwnd, &ps); 00353 00354 // First, draw a frame around the graph. 00355 RECT rect; 00356 GetClientRect(hwnd, &rect); 00357 00358 rect.left += _left_margin; 00359 rect.top += _top_margin; 00360 rect.right -= _right_margin; 00361 rect.bottom -= _bottom_margin; 00362 00363 if (rect.right > rect.left && rect.bottom > rect.top) { 00364 DrawEdge(hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); 00365 00366 int graph_xsize = rect.right - rect.left; 00367 int graph_ysize = rect.bottom - rect.top; 00368 if (_bitmap_dc == 0 || 00369 graph_xsize != _bitmap_xsize || 00370 graph_ysize != _bitmap_ysize) { 00371 // Oops, we need to change the bitmap (and graph) size. 00372 changed_graph_size(graph_xsize, graph_ysize); 00373 move_graph_window(rect.left, rect.top, graph_xsize, graph_ysize); 00374 force_redraw(); 00375 } 00376 } 00377 00378 additional_window_paint(hdc); 00379 00380 EndPaint(hwnd, &ps); 00381 return 0; 00382 } 00383 00384 default: 00385 break; 00386 } 00387 00388 return DefWindowProc(hwnd, msg, wparam, lparam); 00389 } 00390 00391 //////////////////////////////////////////////////////////////////// 00392 // Function: WinStatsGraph::graph_window_proc 00393 // Access: Protected, Virtual 00394 // Description: 00395 //////////////////////////////////////////////////////////////////// 00396 LONG WinStatsGraph:: 00397 graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { 00398 switch (msg) { 00399 case WM_DISPLAYCHANGE: 00400 setup_bitmap(_bitmap_xsize, _bitmap_ysize); 00401 force_redraw(); 00402 break; 00403 00404 case WM_LBUTTONDOWN: 00405 // Vector any uncaught WM_LBUTTONDOWN into the main window, so we 00406 // can drag margins, etc. 00407 if (_potential_drag_mode != DM_none) { 00408 PN_int16 x = LOWORD(lparam) + _graph_left; 00409 PN_int16 y = HIWORD(lparam) + _graph_top; 00410 return window_proc(_window, msg, wparam, MAKELPARAM(x, y)); 00411 } 00412 break; 00413 00414 case WM_LBUTTONUP: 00415 set_drag_mode(DM_none); 00416 ReleaseCapture(); 00417 break; 00418 00419 case WM_PAINT: 00420 { 00421 // Repaint the graph by copying the backing pixmap in. 00422 PAINTSTRUCT ps; 00423 HDC hdc = BeginPaint(hwnd, &ps); 00424 00425 BitBlt(hdc, 0, 0, 00426 _bitmap_xsize, _bitmap_ysize, 00427 _bitmap_dc, 0, 0, 00428 SRCCOPY); 00429 00430 additional_graph_window_paint(hdc); 00431 00432 EndPaint(hwnd, &ps); 00433 return 0; 00434 } 00435 00436 default: 00437 break; 00438 } 00439 00440 return DefWindowProc(hwnd, msg, wparam, lparam); 00441 } 00442 00443 //////////////////////////////////////////////////////////////////// 00444 // Function: WinStatsGraph::additional_window_paint 00445 // Access: Protected, Virtual 00446 // Description: This is called during the servicing of WM_PAINT; it 00447 // gives a derived class opportunity to do some further 00448 // painting into the window (the outer window, not the 00449 // graph window). 00450 //////////////////////////////////////////////////////////////////// 00451 void WinStatsGraph:: 00452 additional_window_paint(HDC hdc) { 00453 } 00454 00455 //////////////////////////////////////////////////////////////////// 00456 // Function: WinStatsGraph::additional_graph_window_paint 00457 // Access: Protected, Virtual 00458 // Description: This is called during the servicing of WM_PAINT; it 00459 // gives a derived class opportunity to do some further 00460 // painting into the graph window. 00461 //////////////////////////////////////////////////////////////////// 00462 void WinStatsGraph:: 00463 additional_graph_window_paint(HDC hdc) { 00464 } 00465 00466 //////////////////////////////////////////////////////////////////// 00467 // Function: WinStatsGraph::consider_drag_start 00468 // Access: Protected, Virtual 00469 // Description: Based on the mouse position within the window's 00470 // client area, look for draggable things the mouse 00471 // might be hovering over and return the appropriate 00472 // DragMode enum or DM_none if nothing is indicated. 00473 //////////////////////////////////////////////////////////////////// 00474 WinStatsGraph::DragMode WinStatsGraph:: 00475 consider_drag_start(int mouse_x, int mouse_y, int width, int height) { 00476 if (mouse_x >= _left_margin - 2 && mouse_x <= _left_margin + 2) { 00477 return DM_left_margin; 00478 } else if (mouse_x >= width - _right_margin - 2 && mouse_x <= width - _right_margin + 2) { 00479 return DM_right_margin; 00480 } 00481 00482 return DM_none; 00483 } 00484 00485 //////////////////////////////////////////////////////////////////// 00486 // Function: WinStatsGraph::set_drag_mode 00487 // Access: Protected, Virtual 00488 // Description: This should be called whenever the drag mode needs to 00489 // change state. It provides hooks for a derived class 00490 // to do something special. 00491 //////////////////////////////////////////////////////////////////// 00492 void WinStatsGraph:: 00493 set_drag_mode(WinStatsGraph::DragMode drag_mode) { 00494 _drag_mode = drag_mode; 00495 } 00496 00497 //////////////////////////////////////////////////////////////////// 00498 // Function: WinStatsGraph::move_graph_window 00499 // Access: Protected, Virtual 00500 // Description: Repositions the graph child window within the parent 00501 // window according to the _margin variables. 00502 //////////////////////////////////////////////////////////////////// 00503 void WinStatsGraph:: 00504 move_graph_window(int graph_left, int graph_top, int graph_xsize, int graph_ysize) { 00505 if (_graph_window == 0) { 00506 create_graph_window(); 00507 } 00508 00509 _graph_left = graph_left; 00510 _graph_top = graph_top; 00511 00512 SetWindowPos(_graph_window, 0, 00513 _graph_left, _graph_top, 00514 graph_xsize, graph_ysize, 00515 SWP_NOZORDER | SWP_SHOWWINDOW); 00516 00517 if (graph_xsize != _bitmap_xsize || graph_ysize != _bitmap_ysize) { 00518 setup_bitmap(graph_xsize, graph_ysize); 00519 } 00520 } 00521 00522 //////////////////////////////////////////////////////////////////// 00523 // Function: WinStatsGraph::setup_bitmap 00524 // Access: Private 00525 // Description: Sets up a backing-store bitmap of the indicated size. 00526 //////////////////////////////////////////////////////////////////// 00527 void WinStatsGraph:: 00528 setup_bitmap(int xsize, int ysize) { 00529 release_bitmap(); 00530 _bitmap_xsize = max(xsize, 0); 00531 _bitmap_ysize = max(ysize, 0); 00532 00533 HDC hdc = GetDC(_graph_window); 00534 _bitmap_dc = CreateCompatibleDC(hdc); 00535 _bitmap = CreateCompatibleBitmap(hdc, _bitmap_xsize, _bitmap_ysize); 00536 SelectObject(_bitmap_dc, _bitmap); 00537 00538 RECT rect = { 0, 0, _bitmap_xsize, _bitmap_ysize }; 00539 FillRect(_bitmap_dc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH)); 00540 00541 ReleaseDC(_window, hdc); 00542 } 00543 00544 //////////////////////////////////////////////////////////////////// 00545 // Function: WinStatsGraph::release_bitmap 00546 // Access: Private 00547 // Description: Frees the backing-store bitmap created by 00548 // setup_bitmap(). 00549 //////////////////////////////////////////////////////////////////// 00550 void WinStatsGraph:: 00551 release_bitmap() { 00552 if (_bitmap) { 00553 DeleteObject(_bitmap); 00554 _bitmap = 0; 00555 } 00556 if (_bitmap_dc) { 00557 DeleteDC(_bitmap_dc); 00558 _bitmap_dc = 0; 00559 } 00560 } 00561 00562 //////////////////////////////////////////////////////////////////// 00563 // Function: WinStatsGraph::create_graph_window 00564 // Access: Private 00565 // Description: Creates the child window that actually holds the graph. 00566 //////////////////////////////////////////////////////////////////// 00567 void WinStatsGraph:: 00568 create_graph_window() { 00569 if (_graph_window) { 00570 return; 00571 } 00572 00573 HINSTANCE application = GetModuleHandle(NULL); 00574 register_graph_window_class(application); 00575 00576 string window_title = "graph"; 00577 DWORD window_style = WS_CHILD | WS_CLIPSIBLINGS; 00578 00579 _graph_window = 00580 CreateWindow(_graph_window_class_name, window_title.c_str(), window_style, 00581 0, 0, 0, 0, 00582 _window, NULL, application, 0); 00583 if (!_graph_window) { 00584 nout << "Could not create graph window!\n"; 00585 exit(1); 00586 } 00587 00588 SetWindowLongPtr(_graph_window, 0, (LONG_PTR)this); 00589 } 00590 00591 //////////////////////////////////////////////////////////////////// 00592 // Function: WinStatsGraph::register_graph_window_class 00593 // Access: Private, Static 00594 // Description: Registers the window class for the stripChart window, if 00595 // it has not already been registered. 00596 //////////////////////////////////////////////////////////////////// 00597 void WinStatsGraph:: 00598 register_graph_window_class(HINSTANCE application) { 00599 if (_graph_window_class_registered) { 00600 return; 00601 } 00602 00603 WNDCLASS wc; 00604 00605 ZeroMemory(&wc, sizeof(WNDCLASS)); 00606 wc.style = CS_DBLCLKS; 00607 wc.lpfnWndProc = (WNDPROC)static_graph_window_proc; 00608 wc.hInstance = application; 00609 wc.hCursor = LoadCursor(NULL, IDC_ARROW); 00610 wc.hbrBackground = NULL; 00611 wc.lpszMenuName = NULL; 00612 wc.lpszClassName = _graph_window_class_name; 00613 00614 // Reserve space to associate the this pointer with the window. 00615 wc.cbWndExtra = sizeof(WinStatsGraph *); 00616 00617 if (!RegisterClass(&wc)) { 00618 nout << "Could not register graph window class!\n"; 00619 exit(1); 00620 } 00621 00622 _graph_window_class_registered = true; 00623 } 00624 00625 //////////////////////////////////////////////////////////////////// 00626 // Function: WinStatsGraph::static_graph_window_proc 00627 // Access: Private, Static 00628 // Description: 00629 //////////////////////////////////////////////////////////////////// 00630 LONG WINAPI WinStatsGraph:: 00631 static_graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { 00632 WinStatsGraph *self = (WinStatsGraph *)GetWindowLongPtr(hwnd, 0); 00633 if (self != (WinStatsGraph *)NULL && self->_graph_window == hwnd) { 00634 return self->graph_window_proc(hwnd, msg, wparam, lparam); 00635 } else { 00636 return DefWindowProc(hwnd, msg, wparam, lparam); 00637 } 00638 }