00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "gtkStatsStripChart.h"
00016 #include "gtkStatsMonitor.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
00027
00028 GtkStatsStripChart::
00029 GtkStatsStripChart(GtkStatsMonitor *monitor, int thread_index,
00030 int collector_index, bool show_level) :
00031 PStatStripChart(monitor,
00032 show_level ? monitor->get_level_view(collector_index, thread_index) : monitor->get_view(thread_index),
00033 thread_index,
00034 collector_index,
00035 default_strip_chart_width,
00036 default_strip_chart_height),
00037 GtkStatsGraph(monitor)
00038 {
00039 _brush_origin = 0;
00040
00041 if (show_level) {
00042
00043 if (_unit_name.empty()) {
00044 set_guide_bar_units(GBU_named);
00045 } else {
00046 set_guide_bar_units(GBU_named | GBU_show_units);
00047 }
00048
00049 } else {
00050
00051 set_guide_bar_units(get_guide_bar_units() | GBU_show_units);
00052 }
00053
00054
00055 _top_hbox = gtk_hbox_new(FALSE, 0);
00056 gtk_box_pack_start(GTK_BOX(_graph_vbox), _top_hbox,
00057 FALSE, FALSE, 0);
00058
00059 _smooth_check_box = gtk_check_button_new_with_label("Smooth");
00060 g_signal_connect(G_OBJECT(_smooth_check_box), "toggled",
00061 G_CALLBACK(toggled_callback), this);
00062
00063 _total_label = gtk_label_new("");
00064 gtk_box_pack_start(GTK_BOX(_top_hbox), _smooth_check_box,
00065 FALSE, FALSE, 0);
00066 gtk_box_pack_end(GTK_BOX(_top_hbox), _total_label,
00067 FALSE, FALSE, 0);
00068
00069
00070
00071 _scale_area = gtk_drawing_area_new();
00072 g_signal_connect(G_OBJECT(_scale_area), "expose_event",
00073 G_CALLBACK(expose_event_callback), this);
00074 gtk_box_pack_start(GTK_BOX(_graph_hbox), _scale_area,
00075 FALSE, FALSE, 0);
00076 gtk_widget_set_size_request(_scale_area, 40, 0);
00077
00078
00079 gtk_widget_set_size_request(_graph_window, default_strip_chart_width,
00080 default_strip_chart_height);
00081
00082 gtk_widget_show_all(_window);
00083 gtk_widget_show(_window);
00084
00085
00086
00087
00088 gtk_widget_set_size_request(_window, 0, 0);
00089
00090 clear_region();
00091 }
00092
00093
00094
00095
00096
00097
00098 GtkStatsStripChart::
00099 ~GtkStatsStripChart() {
00100 }
00101
00102
00103
00104
00105
00106
00107
00108 void GtkStatsStripChart::
00109 new_collector(int collector_index) {
00110 GtkStatsGraph::new_collector(collector_index);
00111 }
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122 void GtkStatsStripChart::
00123 new_data(int thread_index, int frame_number) {
00124 if (is_title_unknown()) {
00125 string window_title = get_title_text();
00126 if (!is_title_unknown()) {
00127 gtk_window_set_title(GTK_WINDOW(_window), window_title.c_str());
00128 }
00129 }
00130
00131 if (!_pause) {
00132 update();
00133
00134 string text = format_number(get_average_net_value(), get_guide_bar_units(), get_guide_bar_unit_name());
00135 if (_net_value_text != text) {
00136 _net_value_text = text;
00137 gtk_label_set_text(GTK_LABEL(_total_label), _net_value_text.c_str());
00138 }
00139 }
00140 }
00141
00142
00143
00144
00145
00146
00147 void GtkStatsStripChart::
00148 force_redraw() {
00149 PStatStripChart::force_redraw();
00150 }
00151
00152
00153
00154
00155
00156
00157
00158 void GtkStatsStripChart::
00159 changed_graph_size(int graph_xsize, int graph_ysize) {
00160 PStatStripChart::changed_size(graph_xsize, graph_ysize);
00161 }
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171 void GtkStatsStripChart::
00172 set_time_units(int unit_mask) {
00173 int old_unit_mask = get_guide_bar_units();
00174 if ((old_unit_mask & (GBU_hz | GBU_ms)) != 0) {
00175 unit_mask = unit_mask & (GBU_hz | GBU_ms);
00176 unit_mask |= (old_unit_mask & GBU_show_units);
00177 set_guide_bar_units(unit_mask);
00178
00179 gtk_widget_queue_draw(_scale_area);
00180 }
00181 }
00182
00183
00184
00185
00186
00187
00188
00189
00190 void GtkStatsStripChart::
00191 set_scroll_speed(double scroll_speed) {
00192
00193 if (scroll_speed != 0.0f) {
00194 set_horizontal_scale(60.0f / scroll_speed);
00195 }
00196 }
00197
00198
00199
00200
00201
00202
00203 void GtkStatsStripChart::
00204 clicked_label(int collector_index) {
00205 if (collector_index < 0) {
00206
00207
00208 collector_index = get_collector_index();
00209 }
00210
00211 if (collector_index == get_collector_index() && collector_index != 0) {
00212
00213 const PStatClientData *client_data =
00214 GtkStatsGraph::_monitor->get_client_data();
00215 if (client_data->has_collector(collector_index)) {
00216 const PStatCollectorDef &def =
00217 client_data->get_collector_def(collector_index);
00218 if (def._parent_index == 0 && get_view().get_show_level()) {
00219
00220 } else {
00221 set_collector_index(def._parent_index);
00222 }
00223 }
00224
00225 } else {
00226
00227 set_collector_index(collector_index);
00228 }
00229 }
00230
00231
00232
00233
00234
00235
00236
00237 void GtkStatsStripChart::
00238 set_vertical_scale(double value_height) {
00239 PStatStripChart::set_vertical_scale(value_height);
00240
00241 gtk_widget_queue_draw(_graph_window);
00242 gtk_widget_queue_draw(_scale_area);
00243 }
00244
00245
00246
00247
00248
00249
00250 void GtkStatsStripChart::
00251 update_labels() {
00252 PStatStripChart::update_labels();
00253
00254 _label_stack.clear_labels();
00255 for (int i = 0; i < get_num_labels(); i++) {
00256 _label_stack.add_label(GtkStatsGraph::_monitor, this, _thread_index,
00257 get_label_collector(i), false);
00258 }
00259 _labels_changed = false;
00260 }
00261
00262
00263
00264
00265
00266
00267 void GtkStatsStripChart::
00268 clear_region() {
00269 gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_white);
00270 gdk_draw_rectangle(_pixmap, _pixmap_gc, TRUE, 0, 0,
00271 get_xsize(), get_ysize());
00272 }
00273
00274
00275
00276
00277
00278
00279
00280
00281 void GtkStatsStripChart::
00282 copy_region(int start_x, int end_x, int dest_x) {
00283 gdk_draw_drawable(_pixmap, _pixmap_gc, _pixmap,
00284 start_x, 0, dest_x, 0,
00285 end_x - start_x, get_ysize());
00286
00287
00288
00289 _brush_origin += (dest_x - start_x);
00290
00291
00292 GdkRectangle rect = {
00293 dest_x, 0, end_x - start_x, get_ysize()
00294 };
00295 gdk_window_invalidate_rect(_graph_window->window, &rect, FALSE);
00296 }
00297
00298
00299
00300
00301
00302
00303
00304
00305 void GtkStatsStripChart::
00306 draw_slice(int x, int w, const PStatStripChart::FrameData &fdata) {
00307
00308 gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_white);
00309 gdk_draw_rectangle(_pixmap, _pixmap_gc, TRUE, x, 0,
00310 w + 1, get_ysize());
00311
00312 double overall_time = 0.0;
00313 int y = get_ysize();
00314
00315 FrameData::const_iterator fi;
00316 for (fi = fdata.begin(); fi != fdata.end(); ++fi) {
00317 const ColorData &cd = (*fi);
00318 overall_time += cd._net_value;
00319 GdkGC *gc = get_collector_gc(cd._collector_index);
00320
00321 if (overall_time > get_vertical_scale()) {
00322
00323
00324 gdk_draw_rectangle(_pixmap, gc, TRUE, x, 0, w, y);
00325
00326 return;
00327 }
00328
00329 int top_y = height_to_pixel(overall_time);
00330 gdk_draw_rectangle(_pixmap, gc, TRUE, x, top_y, w, y - top_y);
00331 y = top_y;
00332 }
00333 }
00334
00335
00336
00337
00338
00339
00340 void GtkStatsStripChart::
00341 draw_empty(int x, int w) {
00342 gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_white);
00343 gdk_draw_rectangle(_pixmap, _pixmap_gc, TRUE, x, 0,
00344 w + 1, get_ysize());
00345 }
00346
00347
00348
00349
00350
00351
00352 void GtkStatsStripChart::
00353 draw_cursor(int x) {
00354 gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_black);
00355 gdk_draw_line(_pixmap, _pixmap_gc, x, 0, x, get_ysize());
00356 }
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366 void GtkStatsStripChart::
00367 end_draw(int from_x, int to_x) {
00368
00369 int num_guide_bars = get_num_guide_bars();
00370 for (int i = 0; i < num_guide_bars; i++) {
00371 draw_guide_bar(_pixmap, from_x, to_x, get_guide_bar(i));
00372 }
00373
00374 GdkRectangle rect = {
00375 from_x, 0, to_x - from_x + 1, get_ysize()
00376 };
00377 gdk_window_invalidate_rect(_graph_window->window, &rect, FALSE);
00378 }
00379
00380
00381
00382
00383
00384
00385
00386
00387 void GtkStatsStripChart::
00388 additional_graph_window_paint() {
00389 int num_user_guide_bars = get_num_user_guide_bars();
00390 for (int i = 0; i < num_user_guide_bars; i++) {
00391 draw_guide_bar(_graph_window->window, 0, get_xsize(), get_user_guide_bar(i));
00392 }
00393 }
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403 GtkStatsGraph::DragMode GtkStatsStripChart::
00404 consider_drag_start(int graph_x, int graph_y) {
00405 if (graph_x >= 0 && graph_x < get_xsize()) {
00406 if (graph_y >= 0 && graph_y < get_ysize()) {
00407
00408 int y = graph_y;
00409 double from_height = pixel_to_height(y + 2);
00410 double to_height = pixel_to_height(y - 2);
00411 _drag_guide_bar = find_user_guide_bar(from_height, to_height);
00412 if (_drag_guide_bar >= 0) {
00413 return DM_guide_bar;
00414 }
00415
00416 } else {
00417
00418
00419 return DM_new_guide_bar;
00420 }
00421 }
00422
00423 return GtkStatsGraph::consider_drag_start(graph_x, graph_y);
00424 }
00425
00426
00427
00428
00429
00430
00431
00432
00433 void GtkStatsStripChart::
00434 set_drag_mode(GtkStatsGraph::DragMode drag_mode) {
00435 GtkStatsGraph::set_drag_mode(drag_mode);
00436
00437 switch (_drag_mode) {
00438 case DM_scale:
00439 case DM_sizing:
00440
00441 set_average_mode(false);
00442 break;
00443
00444 default:
00445
00446
00447 bool active =
00448 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(_smooth_check_box));
00449 set_average_mode(active);
00450 break;
00451 }
00452 }
00453
00454
00455
00456
00457
00458
00459
00460 gboolean GtkStatsStripChart::
00461 handle_button_press(GtkWidget *widget, int graph_x, int graph_y,
00462 bool double_click) {
00463 if (double_click) {
00464
00465
00466 clicked_label(get_collector_under_pixel(graph_x, graph_y));
00467 return TRUE;
00468 }
00469
00470 if (_potential_drag_mode == DM_none) {
00471 set_drag_mode(DM_scale);
00472 _drag_scale_start = pixel_to_height(graph_y);
00473
00474 return TRUE;
00475
00476 } else if (_potential_drag_mode == DM_guide_bar && _drag_guide_bar >= 0) {
00477 set_drag_mode(DM_guide_bar);
00478 _drag_start_y = graph_y;
00479
00480 return TRUE;
00481 }
00482
00483 return GtkStatsGraph::handle_button_press(widget, graph_x, graph_y,
00484 double_click);
00485 }
00486
00487
00488
00489
00490
00491
00492
00493 gboolean GtkStatsStripChart::
00494 handle_button_release(GtkWidget *widget, int graph_x, int graph_y) {
00495 if (_drag_mode == DM_scale) {
00496 set_drag_mode(DM_none);
00497
00498 return handle_motion(widget, graph_x, graph_y);
00499
00500 } else if (_drag_mode == DM_guide_bar) {
00501 if (graph_y < 0 || graph_y >= get_ysize()) {
00502 remove_user_guide_bar(_drag_guide_bar);
00503 } else {
00504 move_user_guide_bar(_drag_guide_bar, pixel_to_height(graph_y));
00505 }
00506 set_drag_mode(DM_none);
00507
00508 return handle_motion(widget, graph_x, graph_y);
00509 }
00510
00511 return GtkStatsGraph::handle_button_release(widget, graph_x, graph_y);
00512 }
00513
00514
00515
00516
00517
00518
00519
00520 gboolean GtkStatsStripChart::
00521 handle_motion(GtkWidget *widget, int graph_x, int graph_y) {
00522 if (_drag_mode == DM_none && _potential_drag_mode == DM_none) {
00523
00524 _label_stack.highlight_label(get_collector_under_pixel(graph_x, graph_y));
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538 } else {
00539
00540 _label_stack.highlight_label(-1);
00541 }
00542
00543 if (_drag_mode == DM_scale) {
00544 double ratio = 1.0f - ((double)graph_y / (double)get_ysize());
00545 if (ratio > 0.0f) {
00546 set_vertical_scale(_drag_scale_start / ratio);
00547 }
00548 return TRUE;
00549
00550 } else if (_drag_mode == DM_new_guide_bar) {
00551
00552
00553 if (graph_y >= 0 && graph_y < get_ysize()) {
00554 set_drag_mode(DM_guide_bar);
00555 _drag_guide_bar = add_user_guide_bar(pixel_to_height(graph_y));
00556 return TRUE;
00557 }
00558
00559 } else if (_drag_mode == DM_guide_bar) {
00560 move_user_guide_bar(_drag_guide_bar, pixel_to_height(graph_y));
00561 return TRUE;
00562 }
00563
00564 return GtkStatsGraph::handle_motion(widget, graph_x, graph_y);
00565 }
00566
00567
00568
00569
00570
00571
00572
00573 void GtkStatsStripChart::
00574 draw_guide_bar(GdkDrawable *surface, int from_x, int to_x,
00575 const PStatGraph::GuideBar &bar) {
00576 int y = height_to_pixel(bar._height);
00577
00578 if (y > 0) {
00579
00580 switch (bar._style) {
00581 case GBS_target:
00582 gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_light_gray);
00583 break;
00584
00585 case GBS_user:
00586 gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_user_guide_bar);
00587 break;
00588
00589 case GBS_normal:
00590 gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_dark_gray);
00591 break;
00592 }
00593 gdk_draw_line(surface, _pixmap_gc, from_x, y, to_x, y);
00594 }
00595 }
00596
00597
00598
00599
00600
00601
00602 void GtkStatsStripChart::
00603 draw_guide_labels() {
00604
00605 int last_y = -100;
00606
00607 int i;
00608 int num_guide_bars = get_num_guide_bars();
00609 for (i = 0; i < num_guide_bars; i++) {
00610 last_y = draw_guide_label(get_guide_bar(i), last_y);
00611 }
00612
00613 GuideBar top_value = make_guide_bar(get_vertical_scale());
00614 draw_guide_label(top_value, last_y);
00615
00616 last_y = -100;
00617 int num_user_guide_bars = get_num_user_guide_bars();
00618 for (i = 0; i < num_user_guide_bars; i++) {
00619 last_y = draw_guide_label(get_user_guide_bar(i), last_y);
00620 }
00621 }
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631 int GtkStatsStripChart::
00632 draw_guide_label(const PStatGraph::GuideBar &bar, int last_y) {
00633 GdkGC *gc = gdk_gc_new(_scale_area->window);
00634
00635 switch (bar._style) {
00636 case GBS_target:
00637 gdk_gc_set_rgb_fg_color(gc, &rgb_light_gray);
00638 break;
00639
00640 case GBS_user:
00641 gdk_gc_set_rgb_fg_color(gc, &rgb_user_guide_bar);
00642 break;
00643
00644 case GBS_normal:
00645 gdk_gc_set_rgb_fg_color(gc, &rgb_dark_gray);
00646 break;
00647 }
00648
00649 int y = height_to_pixel(bar._height);
00650 const string &label = bar._label;
00651
00652 PangoLayout *layout = gtk_widget_create_pango_layout(_window, label.c_str());
00653 int width, height;
00654 pango_layout_get_pixel_size(layout, &width, &height);
00655
00656 if (bar._style != GBS_user) {
00657 double from_height = pixel_to_height(y + height);
00658 double to_height = pixel_to_height(y - height);
00659 if (find_user_guide_bar(from_height, to_height) >= 0) {
00660
00661 g_object_unref(layout);
00662 g_object_unref(gc);
00663 return last_y;
00664 }
00665 }
00666
00667 if (y >= 0 && y < get_ysize()) {
00668
00669 int junk_x;
00670
00671
00672 gtk_widget_translate_coordinates(_graph_window, _scale_area,
00673 0, y,
00674 &junk_x, &y);
00675
00676 int this_y = y - height / 2;
00677 if (last_y < this_y || last_y > this_y + height) {
00678 gdk_draw_layout(_scale_area->window, gc, 0, this_y, layout);
00679 last_y = this_y;
00680 }
00681 }
00682
00683 g_object_unref(layout);
00684 g_object_unref(gc);
00685 return last_y;
00686 }
00687
00688
00689
00690
00691
00692
00693 void GtkStatsStripChart::
00694 toggled_callback(GtkToggleButton *button, gpointer data) {
00695 GtkStatsStripChart *self = (GtkStatsStripChart *)data;
00696
00697 bool active = gtk_toggle_button_get_active(button);
00698 self->set_average_mode(active);
00699 }
00700
00701
00702
00703
00704
00705
00706 gboolean GtkStatsStripChart::
00707 expose_event_callback(GtkWidget *widget, GdkEventExpose *event, gpointer data) {
00708 GtkStatsStripChart *self = (GtkStatsStripChart *)data;
00709 self->draw_guide_labels();
00710
00711 return TRUE;
00712 }