Panda3D
|
00001 // Filename: winStatsStripChart.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 "winStatsStripChart.h" 00016 #include "winStatsMonitor.h" 00017 #include "pStatCollectorDef.h" 00018 #include "numeric_types.h" 00019 00020 static const int default_strip_chart_width = 400; 00021 static const int default_strip_chart_height = 100; 00022 00023 // Surely we aren't expected to hardcode the size of a normal 00024 // checkbox. But Windows seems to require this data to be passed to 00025 // CreateWindow(), so what else can I do? 00026 size_t WinStatsStripChart::_check_box_height = 13; 00027 size_t WinStatsStripChart::_check_box_width = 13; 00028 00029 bool WinStatsStripChart::_window_class_registered = false; 00030 const char * const WinStatsStripChart::_window_class_name = "strip"; 00031 00032 //////////////////////////////////////////////////////////////////// 00033 // Function: WinStatsStripChart::Constructor 00034 // Access: Public 00035 // Description: 00036 //////////////////////////////////////////////////////////////////// 00037 WinStatsStripChart:: 00038 WinStatsStripChart(WinStatsMonitor *monitor, int thread_index, 00039 int collector_index, bool show_level) : 00040 PStatStripChart(monitor, 00041 show_level ? monitor->get_level_view(collector_index, thread_index) : monitor->get_view(thread_index), 00042 thread_index, 00043 collector_index, 00044 default_strip_chart_width, 00045 default_strip_chart_height), 00046 WinStatsGraph(monitor) 00047 { 00048 _brush_origin = 0; 00049 00050 _left_margin = 96; 00051 _right_margin = 32; 00052 _top_margin = 16; 00053 _bottom_margin = 8; 00054 00055 if (show_level) { 00056 // If it's a level-type graph, show the appropriate units. 00057 if (_unit_name.empty()) { 00058 set_guide_bar_units(GBU_named); 00059 } else { 00060 set_guide_bar_units(GBU_named | GBU_show_units); 00061 } 00062 00063 } else { 00064 // If it's a time-type graph, show the ms/Hz units. 00065 set_guide_bar_units(get_guide_bar_units() | GBU_show_units); 00066 } 00067 00068 _smooth_check_box = 0; 00069 00070 create_window(); 00071 clear_region(); 00072 } 00073 00074 //////////////////////////////////////////////////////////////////// 00075 // Function: WinStatsStripChart::Destructor 00076 // Access: Public, Virtual 00077 // Description: 00078 //////////////////////////////////////////////////////////////////// 00079 WinStatsStripChart:: 00080 ~WinStatsStripChart() { 00081 } 00082 00083 //////////////////////////////////////////////////////////////////// 00084 // Function: WinStatsStripChart::new_collector 00085 // Access: Public, Virtual 00086 // Description: Called whenever a new Collector definition is 00087 // received from the client. 00088 //////////////////////////////////////////////////////////////////// 00089 void WinStatsStripChart:: 00090 new_collector(int collector_index) { 00091 WinStatsGraph::new_collector(collector_index); 00092 } 00093 00094 //////////////////////////////////////////////////////////////////// 00095 // Function: WinStatsStripChart::new_data 00096 // Access: Public, Virtual 00097 // Description: Called as each frame's data is made available. There 00098 // is no gurantee the frames will arrive in order, or 00099 // that all of them will arrive at all. The monitor 00100 // should be prepared to accept frames received 00101 // out-of-order or missing. 00102 //////////////////////////////////////////////////////////////////// 00103 void WinStatsStripChart:: 00104 new_data(int thread_index, int frame_number) { 00105 if (is_title_unknown()) { 00106 string window_title = get_title_text(); 00107 if (!is_title_unknown()) { 00108 SetWindowText(_window, window_title.c_str()); 00109 } 00110 } 00111 00112 if (!_pause) { 00113 update(); 00114 00115 string text = format_number(get_average_net_value(), get_guide_bar_units(), get_guide_bar_unit_name()); 00116 if (_net_value_text != text) { 00117 _net_value_text = text; 00118 RECT rect; 00119 GetClientRect(_window, &rect); 00120 rect.bottom = _top_margin; 00121 InvalidateRect(_window, &rect, TRUE); 00122 } 00123 } 00124 } 00125 00126 //////////////////////////////////////////////////////////////////// 00127 // Function: WinStatsStripChart::force_redraw 00128 // Access: Public, Virtual 00129 // Description: Called when it is necessary to redraw the entire graph. 00130 //////////////////////////////////////////////////////////////////// 00131 void WinStatsStripChart:: 00132 force_redraw() { 00133 PStatStripChart::force_redraw(); 00134 } 00135 00136 //////////////////////////////////////////////////////////////////// 00137 // Function: WinStatsStripChart::changed_graph_size 00138 // Access: Public, Virtual 00139 // Description: Called when the user has resized the window, forcing 00140 // a resize of the graph. 00141 //////////////////////////////////////////////////////////////////// 00142 void WinStatsStripChart:: 00143 changed_graph_size(int graph_xsize, int graph_ysize) { 00144 PStatStripChart::changed_size(graph_xsize, graph_ysize); 00145 } 00146 00147 //////////////////////////////////////////////////////////////////// 00148 // Function: WinStatsStripChart::set_time_units 00149 // Access: Public, Virtual 00150 // Description: Called when the user selects a new time units from 00151 // the monitor pulldown menu, this should adjust the 00152 // units for the graph to the indicated mask if it is a 00153 // time-based graph. 00154 //////////////////////////////////////////////////////////////////// 00155 void WinStatsStripChart:: 00156 set_time_units(int unit_mask) { 00157 int old_unit_mask = get_guide_bar_units(); 00158 if ((old_unit_mask & (GBU_hz | GBU_ms)) != 0) { 00159 unit_mask = unit_mask & (GBU_hz | GBU_ms); 00160 unit_mask |= (old_unit_mask & GBU_show_units); 00161 set_guide_bar_units(unit_mask); 00162 00163 RECT rect; 00164 GetClientRect(_window, &rect); 00165 rect.left = _right_margin; 00166 InvalidateRect(_window, &rect, TRUE); 00167 00168 GetClientRect(_window, &rect); 00169 rect.bottom = _top_margin; 00170 InvalidateRect(_window, &rect, TRUE); 00171 } 00172 } 00173 00174 //////////////////////////////////////////////////////////////////// 00175 // Function: WinStatsStripChart::set_scroll_speed 00176 // Access: Public 00177 // Description: Called when the user selects a new scroll speed from 00178 // the monitor pulldown menu, this should adjust the 00179 // speed for the graph to the indicated value. 00180 //////////////////////////////////////////////////////////////////// 00181 void WinStatsStripChart:: 00182 set_scroll_speed(double scroll_speed) { 00183 // The speed factor indicates chart widths per minute. 00184 if (scroll_speed != 0.0f) { 00185 set_horizontal_scale(60.0f / scroll_speed); 00186 } 00187 } 00188 00189 //////////////////////////////////////////////////////////////////// 00190 // Function: WinStatsStripChart::clicked_label 00191 // Access: Public, Virtual 00192 // Description: Called when the user single-clicks on a label. 00193 //////////////////////////////////////////////////////////////////// 00194 void WinStatsStripChart:: 00195 clicked_label(int collector_index) { 00196 if (collector_index < 0) { 00197 // Clicking on whitespace in the graph is the same as clicking on 00198 // the top label. 00199 collector_index = get_collector_index(); 00200 } 00201 00202 if (collector_index == get_collector_index() && collector_index != 0) { 00203 // Clicking on the top label means to go up to the parent level. 00204 const PStatClientData *client_data = 00205 WinStatsGraph::_monitor->get_client_data(); 00206 if (client_data->has_collector(collector_index)) { 00207 const PStatCollectorDef &def = 00208 client_data->get_collector_def(collector_index); 00209 if (def._parent_index == 0 && get_view().get_show_level()) { 00210 // Unless the parent is "Frame", and we're not a time collector. 00211 } else { 00212 set_collector_index(def._parent_index); 00213 } 00214 } 00215 00216 } else { 00217 // Clicking on any other label means to focus on that. 00218 set_collector_index(collector_index); 00219 } 00220 } 00221 00222 //////////////////////////////////////////////////////////////////// 00223 // Function: WinStatsStripChart::set_vertical_scale 00224 // Access: Public 00225 // Description: Changes the value the height of the vertical axis 00226 // represents. This may force a redraw. 00227 //////////////////////////////////////////////////////////////////// 00228 void WinStatsStripChart:: 00229 set_vertical_scale(double value_height) { 00230 PStatStripChart::set_vertical_scale(value_height); 00231 00232 RECT rect; 00233 GetClientRect(_window, &rect); 00234 rect.left = _right_margin; 00235 InvalidateRect(_window, &rect, TRUE); 00236 } 00237 00238 //////////////////////////////////////////////////////////////////// 00239 // Function: WinStatsStripChart::update_labels 00240 // Access: Protected, Virtual 00241 // Description: Resets the list of labels. 00242 //////////////////////////////////////////////////////////////////// 00243 void WinStatsStripChart:: 00244 update_labels() { 00245 PStatStripChart::update_labels(); 00246 00247 _label_stack.clear_labels(); 00248 for (int i = 0; i < get_num_labels(); i++) { 00249 _label_stack.add_label(WinStatsGraph::_monitor, this, _thread_index, 00250 get_label_collector(i), false); 00251 } 00252 _labels_changed = false; 00253 } 00254 00255 //////////////////////////////////////////////////////////////////// 00256 // Function: WinStatsStripChart::clear_region 00257 // Access: Protected, Virtual 00258 // Description: Erases the chart area. 00259 //////////////////////////////////////////////////////////////////// 00260 void WinStatsStripChart:: 00261 clear_region() { 00262 RECT rect = { 0, 0, get_xsize(), get_ysize() }; 00263 FillRect(_bitmap_dc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH)); 00264 } 00265 00266 //////////////////////////////////////////////////////////////////// 00267 // Function: WinStatsStripChart::copy_region 00268 // Access: Protected, Virtual 00269 // Description: Should be overridden by the user class to copy a 00270 // region of the chart from one part of the chart to 00271 // another. This is used to implement scrolling. 00272 //////////////////////////////////////////////////////////////////// 00273 void WinStatsStripChart:: 00274 copy_region(int start_x, int end_x, int dest_x) { 00275 BitBlt(_bitmap_dc, dest_x, 0, 00276 end_x - start_x, get_ysize(), 00277 _bitmap_dc, start_x, 0, 00278 SRCCOPY); 00279 00280 // Also shift the brush origin over, so we still get proper 00281 // dithering. 00282 _brush_origin += (dest_x - start_x); 00283 SetBrushOrgEx(_bitmap_dc, _brush_origin, 0, NULL); 00284 00285 RECT rect = { 00286 dest_x, 0, dest_x + end_x - start_x, get_ysize() 00287 }; 00288 InvalidateRect(_graph_window, &rect, FALSE); 00289 } 00290 00291 //////////////////////////////////////////////////////////////////// 00292 // Function: WinStatsStripChart::draw_slice 00293 // Access: Protected, Virtual 00294 // Description: Draws a single vertical slice of the strip chart, at 00295 // the given pixel position, and corresponding to the 00296 // indicated level data. 00297 //////////////////////////////////////////////////////////////////// 00298 void WinStatsStripChart:: 00299 draw_slice(int x, int w, const PStatStripChart::FrameData &fdata) { 00300 // Start by clearing the band first. 00301 RECT rect = { x, 0, x + w, get_ysize() }; 00302 FillRect(_bitmap_dc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH)); 00303 00304 double overall_time = 0.0; 00305 int y = get_ysize(); 00306 00307 FrameData::const_iterator fi; 00308 for (fi = fdata.begin(); fi != fdata.end(); ++fi) { 00309 const ColorData &cd = (*fi); 00310 overall_time += cd._net_value; 00311 HBRUSH brush = get_collector_brush(cd._collector_index); 00312 00313 if (overall_time > get_vertical_scale()) { 00314 // Off the top. Go ahead and clamp it by hand, in case it's so 00315 // far off the top we'd overflow the 16-bit pixel value. 00316 rect.top = 0; 00317 rect.bottom = y; 00318 FillRect(_bitmap_dc, &rect, brush); 00319 // And we can consider ourselves done now. 00320 return; 00321 } 00322 00323 int top_y = height_to_pixel(overall_time); 00324 rect.top = top_y; 00325 rect.bottom = y; 00326 FillRect(_bitmap_dc, &rect, brush); 00327 y = top_y; 00328 } 00329 } 00330 00331 //////////////////////////////////////////////////////////////////// 00332 // Function: WinStatsStripChart::draw_empty 00333 // Access: Protected, Virtual 00334 // Description: Draws a single vertical slice of background color. 00335 //////////////////////////////////////////////////////////////////// 00336 void WinStatsStripChart:: 00337 draw_empty(int x, int w) { 00338 RECT rect = { x, 0, x + w, get_ysize() }; 00339 FillRect(_bitmap_dc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH)); 00340 } 00341 00342 //////////////////////////////////////////////////////////////////// 00343 // Function: WinStatsStripChart::draw_cursor 00344 // Access: Protected, Virtual 00345 // Description: Draws a single vertical slice of foreground color. 00346 //////////////////////////////////////////////////////////////////// 00347 void WinStatsStripChart:: 00348 draw_cursor(int x) { 00349 RECT rect = { x, 0, x + 1, get_ysize() }; 00350 FillRect(_bitmap_dc, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH)); 00351 } 00352 00353 //////////////////////////////////////////////////////////////////// 00354 // Function: WinStatsStripChart::end_draw 00355 // Access: Protected, Virtual 00356 // Description: Should be overridden by the user class. This hook 00357 // will be called after drawing a series of color bars 00358 // in the strip chart; it gives the pixel range that 00359 // was just redrawn. 00360 //////////////////////////////////////////////////////////////////// 00361 void WinStatsStripChart:: 00362 end_draw(int from_x, int to_x) { 00363 // Draw in the guide bars. 00364 int num_guide_bars = get_num_guide_bars(); 00365 for (int i = 0; i < num_guide_bars; i++) { 00366 draw_guide_bar(_bitmap_dc, from_x, to_x, get_guide_bar(i)); 00367 } 00368 00369 RECT rect = { 00370 from_x, 0, to_x + 1, get_ysize() 00371 }; 00372 InvalidateRect(_graph_window, &rect, FALSE); 00373 } 00374 00375 //////////////////////////////////////////////////////////////////// 00376 // Function: WinStatsStripChart::window_proc 00377 // Access: Protected 00378 // Description: 00379 //////////////////////////////////////////////////////////////////// 00380 LONG WinStatsStripChart:: 00381 window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { 00382 switch (msg) { 00383 case WM_LBUTTONDOWN: 00384 if (_potential_drag_mode == DM_new_guide_bar) { 00385 set_drag_mode(DM_new_guide_bar); 00386 SetCapture(_graph_window); 00387 return 0; 00388 } 00389 break; 00390 00391 case WM_COMMAND: 00392 switch (LOWORD(wparam)) { 00393 case BN_CLICKED: 00394 if ((HWND)lparam == _smooth_check_box) { 00395 int result = SendMessage(_smooth_check_box, BM_GETCHECK, 0, 0); 00396 set_average_mode(result == BST_CHECKED); 00397 return 0; 00398 } 00399 break; 00400 } 00401 break; 00402 00403 default: 00404 break; 00405 } 00406 00407 return WinStatsGraph::window_proc(hwnd, msg, wparam, lparam); 00408 } 00409 00410 //////////////////////////////////////////////////////////////////// 00411 // Function: WinStatsStripChart::graph_window_proc 00412 // Access: Protected 00413 // Description: 00414 //////////////////////////////////////////////////////////////////// 00415 LONG WinStatsStripChart:: 00416 graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { 00417 switch (msg) { 00418 case WM_LBUTTONDOWN: 00419 if (_potential_drag_mode == DM_none) { 00420 set_drag_mode(DM_scale); 00421 PN_int16 y = HIWORD(lparam); 00422 _drag_scale_start = pixel_to_height(y); 00423 SetCapture(_graph_window); 00424 return 0; 00425 00426 } else if (_potential_drag_mode == DM_guide_bar && _drag_guide_bar >= 0) { 00427 set_drag_mode(DM_guide_bar); 00428 PN_int16 y = HIWORD(lparam); 00429 _drag_start_y = y; 00430 SetCapture(_graph_window); 00431 return 0; 00432 } 00433 break; 00434 00435 case WM_MOUSEMOVE: 00436 if (_drag_mode == DM_none && _potential_drag_mode == DM_none) { 00437 // When the mouse is over a color bar, highlight it. 00438 PN_int16 x = LOWORD(lparam); 00439 PN_int16 y = HIWORD(lparam); 00440 _label_stack.highlight_label(get_collector_under_pixel(x, y)); 00441 00442 // Now we want to get a WM_MOUSELEAVE when the mouse leaves the 00443 // graph window. 00444 TRACKMOUSEEVENT tme = { 00445 sizeof(TRACKMOUSEEVENT), 00446 TME_LEAVE, 00447 _graph_window, 00448 0 00449 }; 00450 TrackMouseEvent(&tme); 00451 00452 } else { 00453 // If the mouse is in some drag mode, stop highlighting. 00454 _label_stack.highlight_label(-1); 00455 } 00456 00457 if (_drag_mode == DM_scale) { 00458 PN_int16 y = HIWORD(lparam); 00459 double ratio = 1.0f - ((double)y / (double)get_ysize()); 00460 if (ratio > 0.0f) { 00461 set_vertical_scale(_drag_scale_start / ratio); 00462 } 00463 return 0; 00464 00465 } else if (_drag_mode == DM_new_guide_bar) { 00466 // We haven't created the new guide bar yet; we won't until the 00467 // mouse comes within the graph's region. 00468 PN_int16 y = HIWORD(lparam); 00469 if (y >= 0 && y < get_ysize()) { 00470 set_drag_mode(DM_guide_bar); 00471 _drag_guide_bar = add_user_guide_bar(pixel_to_height(y)); 00472 return 0; 00473 } 00474 00475 } else if (_drag_mode == DM_guide_bar) { 00476 PN_int16 y = HIWORD(lparam); 00477 move_user_guide_bar(_drag_guide_bar, pixel_to_height(y)); 00478 return 0; 00479 } 00480 break; 00481 00482 case WM_MOUSELEAVE: 00483 // When the mouse leaves the graph, stop highlighting. 00484 _label_stack.highlight_label(-1); 00485 break; 00486 00487 case WM_LBUTTONUP: 00488 if (_drag_mode == DM_scale) { 00489 set_drag_mode(DM_none); 00490 ReleaseCapture(); 00491 return 0; 00492 00493 } else if (_drag_mode == DM_guide_bar) { 00494 PN_int16 y = HIWORD(lparam); 00495 if (y < 0 || y >= get_ysize()) { 00496 remove_user_guide_bar(_drag_guide_bar); 00497 } else { 00498 move_user_guide_bar(_drag_guide_bar, pixel_to_height(y)); 00499 } 00500 set_drag_mode(DM_none); 00501 ReleaseCapture(); 00502 return 0; 00503 } 00504 break; 00505 00506 case WM_LBUTTONDBLCLK: 00507 { 00508 // Double-clicking on a color bar in the graph is the same as 00509 // double-clicking on the corresponding label. 00510 PN_int16 x = LOWORD(lparam); 00511 PN_int16 y = HIWORD(lparam); 00512 clicked_label(get_collector_under_pixel(x, y)); 00513 return 0; 00514 } 00515 break; 00516 00517 default: 00518 break; 00519 } 00520 00521 return WinStatsGraph::graph_window_proc(hwnd, msg, wparam, lparam); 00522 } 00523 00524 //////////////////////////////////////////////////////////////////// 00525 // Function: WinStatsStripChart::additional_window_paint 00526 // Access: Protected, Virtual 00527 // Description: This is called during the servicing of WM_PAINT; it 00528 // gives a derived class opportunity to do some further 00529 // painting into the window (the outer window, not the 00530 // graph window). 00531 //////////////////////////////////////////////////////////////////// 00532 void WinStatsStripChart:: 00533 additional_window_paint(HDC hdc) { 00534 // Draw in the labels for the guide bars. 00535 HFONT hfnt = (HFONT)GetStockObject(ANSI_VAR_FONT); 00536 SelectObject(hdc, hfnt); 00537 SetTextAlign(hdc, TA_LEFT | TA_TOP); 00538 SetBkMode(hdc, TRANSPARENT); 00539 00540 RECT rect; 00541 GetClientRect(_window, &rect); 00542 int x = rect.right - _right_margin + 2; 00543 int last_y = -100; 00544 00545 int i; 00546 int num_guide_bars = get_num_guide_bars(); 00547 for (i = 0; i < num_guide_bars; i++) { 00548 last_y = draw_guide_label(hdc, x, get_guide_bar(i), last_y); 00549 } 00550 00551 GuideBar top_value = make_guide_bar(get_vertical_scale()); 00552 draw_guide_label(hdc, x, top_value, last_y); 00553 00554 last_y = -100; 00555 int num_user_guide_bars = get_num_user_guide_bars(); 00556 for (i = 0; i < num_user_guide_bars; i++) { 00557 last_y = draw_guide_label(hdc, x, get_user_guide_bar(i), last_y); 00558 } 00559 00560 // Now draw the "net value" label at the top. 00561 SetTextAlign(hdc, TA_RIGHT | TA_BOTTOM); 00562 SetTextColor(hdc, RGB(0, 0, 0)); 00563 TextOut(hdc, rect.right - _right_margin, _top_margin, 00564 _net_value_text.data(), _net_value_text.length()); 00565 00566 // Also draw the "Smooth" label on the check box. This isn't part 00567 // of the check box itself, because doing that doesn't use the right 00568 // font! Surely this isn't the correct Windows(tm) way to do this 00569 // sort of thing, but I don't know any better for now. 00570 SetTextAlign(hdc, TA_LEFT | TA_BOTTOM); 00571 TextOut(hdc, _left_margin + _check_box_width + 2, _top_margin, "Smooth", 6); 00572 } 00573 00574 //////////////////////////////////////////////////////////////////// 00575 // Function: WinStatsStripChart::additional_graph_window_paint 00576 // Access: Protected, Virtual 00577 // Description: This is called during the servicing of WM_PAINT; it 00578 // gives a derived class opportunity to do some further 00579 // painting into the window (the outer window, not the 00580 // graph window). 00581 //////////////////////////////////////////////////////////////////// 00582 void WinStatsStripChart:: 00583 additional_graph_window_paint(HDC hdc) { 00584 int num_user_guide_bars = get_num_user_guide_bars(); 00585 for (int i = 0; i < num_user_guide_bars; i++) { 00586 draw_guide_bar(hdc, 0, get_xsize(), get_user_guide_bar(i)); 00587 } 00588 } 00589 00590 //////////////////////////////////////////////////////////////////// 00591 // Function: WinStatsStripChart::consider_drag_start 00592 // Access: Protected, Virtual 00593 // Description: Based on the mouse position within the window's 00594 // client area, look for draggable things the mouse 00595 // might be hovering over and return the apprioprate 00596 // DragMode enum or DM_none if nothing is indicated. 00597 //////////////////////////////////////////////////////////////////// 00598 WinStatsGraph::DragMode WinStatsStripChart:: 00599 consider_drag_start(int mouse_x, int mouse_y, int width, int height) { 00600 if (mouse_x >= _graph_left && mouse_x < _graph_left + get_xsize()) { 00601 if (mouse_y >= _graph_top && mouse_y < _graph_top + get_ysize()) { 00602 // See if the mouse is over a user-defined guide bar. 00603 int y = mouse_y - _graph_top; 00604 double from_height = pixel_to_height(y + 2); 00605 double to_height = pixel_to_height(y - 2); 00606 _drag_guide_bar = find_user_guide_bar(from_height, to_height); 00607 if (_drag_guide_bar >= 0) { 00608 return DM_guide_bar; 00609 } 00610 00611 } else { 00612 // The mouse is above or below the graph; maybe create a new 00613 // guide bar. 00614 return DM_new_guide_bar; 00615 } 00616 } 00617 00618 return WinStatsGraph::consider_drag_start(mouse_x, mouse_y, width, height); 00619 } 00620 00621 //////////////////////////////////////////////////////////////////// 00622 // Function: WinStatsStripChart::set_drag_mode 00623 // Access: Protected, Virtual 00624 // Description: This should be called whenever the drag mode needs to 00625 // change state. It provides hooks for a derived class 00626 // to do something special. 00627 //////////////////////////////////////////////////////////////////// 00628 void WinStatsStripChart:: 00629 set_drag_mode(WinStatsGraph::DragMode drag_mode) { 00630 WinStatsGraph::set_drag_mode(drag_mode); 00631 00632 switch (_drag_mode) { 00633 case DM_scale: 00634 case DM_left_margin: 00635 case DM_right_margin: 00636 case DM_sizing: 00637 // Disable smoothing for these expensive operations. 00638 set_average_mode(false); 00639 break; 00640 00641 default: 00642 // Restore smoothing according to the current setting of the check 00643 // box. 00644 int result = SendMessage(_smooth_check_box, BM_GETCHECK, 0, 0); 00645 set_average_mode(result == BST_CHECKED); 00646 } 00647 } 00648 00649 //////////////////////////////////////////////////////////////////// 00650 // Function: WinStatsStripChart::move_graph_window 00651 // Access: Protected, Virtual 00652 // Description: Repositions the graph child window within the parent 00653 // window according to the _margin variables. 00654 //////////////////////////////////////////////////////////////////// 00655 void WinStatsStripChart:: 00656 move_graph_window(int graph_left, int graph_top, int graph_xsize, int graph_ysize) { 00657 WinStatsGraph::move_graph_window(graph_left, graph_top, graph_xsize, graph_ysize); 00658 if (_smooth_check_box != 0) { 00659 SetWindowPos(_smooth_check_box, 0, 00660 _left_margin, _top_margin - _check_box_height - 1, 00661 0, 0, 00662 SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW); 00663 InvalidateRect(_smooth_check_box, NULL, TRUE); 00664 } 00665 } 00666 00667 //////////////////////////////////////////////////////////////////// 00668 // Function: WinStatsStripChart::draw_guide_bar 00669 // Access: Private 00670 // Description: Draws the line for the indicated guide bar on the 00671 // graph. 00672 //////////////////////////////////////////////////////////////////// 00673 void WinStatsStripChart:: 00674 draw_guide_bar(HDC hdc, int from_x, int to_x, 00675 const PStatGraph::GuideBar &bar) { 00676 int y = height_to_pixel(bar._height); 00677 00678 if (y > 0) { 00679 // Only draw it if it's not too close to the top. 00680 switch (bar._style) { 00681 case GBS_target: 00682 SelectObject(hdc, _light_pen); 00683 break; 00684 00685 case GBS_user: 00686 SelectObject(hdc, _user_guide_bar_pen); 00687 break; 00688 00689 case GBS_normal: 00690 SelectObject(hdc, _dark_pen); 00691 break; 00692 } 00693 MoveToEx(hdc, from_x, y, NULL); 00694 LineTo(hdc, to_x + 1, y); 00695 } 00696 } 00697 00698 //////////////////////////////////////////////////////////////////// 00699 // Function: WinStatsStripChart::draw_guide_label 00700 // Access: Private 00701 // Description: Draws the text for the indicated guide bar label to 00702 // the right of the graph, unless it would overlap with 00703 // the indicated last label, whose top pixel value is 00704 // given. Returns the top pixel value of the new label. 00705 //////////////////////////////////////////////////////////////////// 00706 int WinStatsStripChart:: 00707 draw_guide_label(HDC hdc, int x, const PStatGraph::GuideBar &bar, int last_y) { 00708 switch (bar._style) { 00709 case GBS_target: 00710 SetTextColor(hdc, _light_color); 00711 break; 00712 00713 case GBS_user: 00714 SetTextColor(hdc, _user_guide_bar_color); 00715 break; 00716 00717 case GBS_normal: 00718 SetTextColor(hdc, _dark_color); 00719 break; 00720 } 00721 00722 int y = height_to_pixel(bar._height); 00723 const string &label = bar._label; 00724 SIZE size; 00725 GetTextExtentPoint32(hdc, label.data(), label.length(), &size); 00726 00727 if (bar._style != GBS_user) { 00728 double from_height = pixel_to_height(y + size.cy); 00729 double to_height = pixel_to_height(y - size.cy); 00730 if (find_user_guide_bar(from_height, to_height) >= 0) { 00731 // Omit the label: there's a user-defined guide bar in the same space. 00732 return last_y; 00733 } 00734 } 00735 00736 int this_y = _graph_top + y - size.cy / 2; 00737 if (y >= 0 && y < get_ysize() && 00738 (last_y < this_y || last_y > this_y + size.cy)) { 00739 TextOut(hdc, x, this_y, 00740 label.data(), label.length()); 00741 last_y = this_y; 00742 } 00743 00744 return last_y; 00745 } 00746 00747 00748 //////////////////////////////////////////////////////////////////// 00749 // Function: WinStatsStripChart::create_window 00750 // Access: Private 00751 // Description: Creates the window for this strip chart. 00752 //////////////////////////////////////////////////////////////////// 00753 void WinStatsStripChart:: 00754 create_window() { 00755 if (_window) { 00756 return; 00757 } 00758 00759 HINSTANCE application = GetModuleHandle(NULL); 00760 register_window_class(application); 00761 00762 string window_title = get_title_text(); 00763 00764 RECT win_rect = { 00765 0, 0, 00766 _left_margin + get_xsize() + _right_margin, 00767 _top_margin + get_ysize() + _bottom_margin 00768 }; 00769 00770 // compute window size based on desired client area size 00771 AdjustWindowRect(&win_rect, graph_window_style, FALSE); 00772 00773 _window = 00774 CreateWindow(_window_class_name, window_title.c_str(), graph_window_style, 00775 CW_USEDEFAULT, CW_USEDEFAULT, 00776 win_rect.right - win_rect.left, 00777 win_rect.bottom - win_rect.top, 00778 WinStatsGraph::_monitor->get_window(), NULL, application, 0); 00779 if (!_window) { 00780 nout << "Could not create StripChart window!\n"; 00781 exit(1); 00782 } 00783 00784 SetWindowLongPtr(_window, 0, (LONG_PTR)this); 00785 setup_label_stack(); 00786 00787 _smooth_check_box = 00788 CreateWindow("BUTTON", "", 00789 WS_CHILD | BS_AUTOCHECKBOX, 00790 0, 0, _check_box_width, _check_box_height, 00791 _window, NULL, application, 0); 00792 00793 // Ensure that the window is on top of the stack. 00794 SetWindowPos(_window, HWND_TOP, 0, 0, 0, 0, 00795 SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); 00796 } 00797 00798 //////////////////////////////////////////////////////////////////// 00799 // Function: WinStatsStripChart::register_window_class 00800 // Access: Private, Static 00801 // Description: Registers the window class for the stripChart window, if 00802 // it has not already been registered. 00803 //////////////////////////////////////////////////////////////////// 00804 void WinStatsStripChart:: 00805 register_window_class(HINSTANCE application) { 00806 if (_window_class_registered) { 00807 return; 00808 } 00809 00810 WNDCLASS wc; 00811 00812 ZeroMemory(&wc, sizeof(WNDCLASS)); 00813 wc.style = 0; 00814 wc.lpfnWndProc = (WNDPROC)static_window_proc; 00815 wc.hInstance = application; 00816 wc.hCursor = LoadCursor(NULL, IDC_ARROW); 00817 wc.hbrBackground = (HBRUSH)COLOR_BACKGROUND; 00818 wc.lpszMenuName = NULL; 00819 wc.lpszClassName = _window_class_name; 00820 00821 // Reserve space to associate the this pointer with the window. 00822 wc.cbWndExtra = sizeof(WinStatsStripChart *); 00823 00824 if (!RegisterClass(&wc)) { 00825 nout << "Could not register StripChart window class!\n"; 00826 exit(1); 00827 } 00828 00829 _window_class_registered = true; 00830 } 00831 00832 //////////////////////////////////////////////////////////////////// 00833 // Function: WinStatsStripChart::static_window_proc 00834 // Access: Private, Static 00835 // Description: 00836 //////////////////////////////////////////////////////////////////// 00837 LONG WINAPI WinStatsStripChart:: 00838 static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { 00839 WinStatsStripChart *self = (WinStatsStripChart *)GetWindowLongPtr(hwnd, 0); 00840 if (self != (WinStatsStripChart *)NULL && self->_window == hwnd) { 00841 return self->window_proc(hwnd, msg, wparam, lparam); 00842 } else { 00843 return DefWindowProc(hwnd, msg, wparam, lparam); 00844 } 00845 }