00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
00024
00025
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
00034
00035
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
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
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
00076
00077
00078
00079 WinStatsStripChart::
00080 ~WinStatsStripChart() {
00081 }
00082
00083
00084
00085
00086
00087
00088
00089 void WinStatsStripChart::
00090 new_collector(int collector_index) {
00091 WinStatsGraph::new_collector(collector_index);
00092 }
00093
00094
00095
00096
00097
00098
00099
00100
00101
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
00128
00129
00130
00131 void WinStatsStripChart::
00132 force_redraw() {
00133 PStatStripChart::force_redraw();
00134 }
00135
00136
00137
00138
00139
00140
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
00149
00150
00151
00152
00153
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
00176
00177
00178
00179
00180
00181 void WinStatsStripChart::
00182 set_scroll_speed(double scroll_speed) {
00183
00184 if (scroll_speed != 0.0f) {
00185 set_horizontal_scale(60.0f / scroll_speed);
00186 }
00187 }
00188
00189
00190
00191
00192
00193
00194 void WinStatsStripChart::
00195 clicked_label(int collector_index) {
00196 if (collector_index < 0) {
00197
00198
00199 collector_index = get_collector_index();
00200 }
00201
00202 if (collector_index == get_collector_index() && collector_index != 0) {
00203
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
00211 } else {
00212 set_collector_index(def._parent_index);
00213 }
00214 }
00215
00216 } else {
00217
00218 set_collector_index(collector_index);
00219 }
00220 }
00221
00222
00223
00224
00225
00226
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
00240
00241
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
00257
00258
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
00268
00269
00270
00271
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
00281
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
00293
00294
00295
00296
00297
00298 void WinStatsStripChart::
00299 draw_slice(int x, int w, const PStatStripChart::FrameData &fdata) {
00300
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
00315
00316 rect.top = 0;
00317 rect.bottom = y;
00318 FillRect(_bitmap_dc, &rect, brush);
00319
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
00333
00334
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
00344
00345
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
00355
00356
00357
00358
00359
00360
00361 void WinStatsStripChart::
00362 end_draw(int from_x, int to_x) {
00363
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
00377
00378
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
00412
00413
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
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
00443
00444 TRACKMOUSEEVENT tme = {
00445 sizeof(TRACKMOUSEEVENT),
00446 TME_LEAVE,
00447 _graph_window,
00448 0
00449 };
00450 TrackMouseEvent(&tme);
00451
00452 } else {
00453
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
00467
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
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
00509
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
00526
00527
00528
00529
00530
00531
00532 void WinStatsStripChart::
00533 additional_window_paint(HDC hdc) {
00534
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
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
00567
00568
00569
00570 SetTextAlign(hdc, TA_LEFT | TA_BOTTOM);
00571 TextOut(hdc, _left_margin + _check_box_width + 2, _top_margin, "Smooth", 6);
00572 }
00573
00574
00575
00576
00577
00578
00579
00580
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
00592
00593
00594
00595
00596
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
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
00613
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
00623
00624
00625
00626
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
00638 set_average_mode(false);
00639 break;
00640
00641 default:
00642
00643
00644 int result = SendMessage(_smooth_check_box, BM_GETCHECK, 0, 0);
00645 set_average_mode(result == BST_CHECKED);
00646 }
00647 }
00648
00649
00650
00651
00652
00653
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
00669
00670
00671
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
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
00700
00701
00702
00703
00704
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
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
00750
00751
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
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
00794 SetWindowPos(_window, HWND_TOP, 0, 0, 0, 0,
00795 SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
00796 }
00797
00798
00799
00800
00801
00802
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
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
00834
00835
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 }