00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "gtkStatsPianoRoll.h"
00016 #include "gtkStatsMonitor.h"
00017 #include "numeric_types.h"
00018 #include "gtkStatsLabelStack.h"
00019
00020 static const int default_piano_roll_width = 400;
00021 static const int default_piano_roll_height = 200;
00022
00023
00024
00025
00026
00027
00028 GtkStatsPianoRoll::
00029 GtkStatsPianoRoll(GtkStatsMonitor *monitor, int thread_index) :
00030 PStatPianoRoll(monitor, thread_index,
00031 default_piano_roll_width,
00032 default_piano_roll_height),
00033 GtkStatsGraph(monitor)
00034 {
00035
00036 set_guide_bar_units(get_guide_bar_units() | GBU_show_units);
00037
00038
00039
00040 _scale_area = gtk_drawing_area_new();
00041 g_signal_connect(G_OBJECT(_scale_area), "expose_event",
00042 G_CALLBACK(expose_event_callback), this);
00043 gtk_box_pack_start(GTK_BOX(_graph_vbox), _scale_area,
00044 FALSE, FALSE, 0);
00045 gtk_widget_set_size_request(_scale_area, 0, 20);
00046
00047
00048 gtk_widget_set_size_request(_graph_window, default_piano_roll_width,
00049 default_piano_roll_height);
00050
00051 const PStatClientData *client_data =
00052 GtkStatsGraph::_monitor->get_client_data();
00053 string thread_name = client_data->get_thread_name(_thread_index);
00054 string window_title = thread_name + " thread piano roll";
00055 gtk_window_set_title(GTK_WINDOW(_window), window_title.c_str());
00056
00057 gtk_widget_show_all(_window);
00058 gtk_widget_show(_window);
00059
00060
00061
00062
00063 gtk_widget_set_size_request(_window, 0, 0);
00064
00065 clear_region();
00066 }
00067
00068
00069
00070
00071
00072
00073 GtkStatsPianoRoll::
00074 ~GtkStatsPianoRoll() {
00075 }
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086 void GtkStatsPianoRoll::
00087 new_data(int thread_index, int frame_number) {
00088 if (!_pause) {
00089 update();
00090 }
00091 }
00092
00093
00094
00095
00096
00097
00098 void GtkStatsPianoRoll::
00099 force_redraw() {
00100 PStatPianoRoll::force_redraw();
00101 }
00102
00103
00104
00105
00106
00107
00108
00109 void GtkStatsPianoRoll::
00110 changed_graph_size(int graph_xsize, int graph_ysize) {
00111 PStatPianoRoll::changed_size(graph_xsize, graph_ysize);
00112 }
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122 void GtkStatsPianoRoll::
00123 set_time_units(int unit_mask) {
00124 int old_unit_mask = get_guide_bar_units();
00125 if ((old_unit_mask & (GBU_hz | GBU_ms)) != 0) {
00126 unit_mask = unit_mask & (GBU_hz | GBU_ms);
00127 unit_mask |= (old_unit_mask & GBU_show_units);
00128 set_guide_bar_units(unit_mask);
00129
00130 gtk_widget_queue_draw(_scale_area);
00131 }
00132 }
00133
00134
00135
00136
00137
00138
00139 void GtkStatsPianoRoll::
00140 clicked_label(int collector_index) {
00141 if (collector_index >= 0) {
00142 GtkStatsGraph::_monitor->open_strip_chart(_thread_index, collector_index, false);
00143 }
00144 }
00145
00146
00147
00148
00149
00150
00151
00152 void GtkStatsPianoRoll::
00153 set_horizontal_scale(double time_width) {
00154 PStatPianoRoll::set_horizontal_scale(time_width);
00155
00156 gtk_widget_queue_draw(_graph_window);
00157 gtk_widget_queue_draw(_scale_area);
00158 }
00159
00160
00161
00162
00163
00164
00165 void GtkStatsPianoRoll::
00166 clear_region() {
00167 gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_white);
00168 gdk_draw_rectangle(_pixmap, _pixmap_gc, TRUE, 0, 0,
00169 get_xsize(), get_ysize());
00170 }
00171
00172
00173
00174
00175
00176
00177
00178 void GtkStatsPianoRoll::
00179 begin_draw() {
00180 clear_region();
00181
00182
00183 int num_guide_bars = get_num_guide_bars();
00184 for (int i = 0; i < num_guide_bars; i++) {
00185 draw_guide_bar(_pixmap, get_guide_bar(i));
00186 }
00187 }
00188
00189
00190
00191
00192
00193
00194 void GtkStatsPianoRoll::
00195 draw_bar(int row, int from_x, int to_x) {
00196 if (row >= 0 && row < _label_stack.get_num_labels()) {
00197 int y = _label_stack.get_label_y(row, _graph_window);
00198 int height = _label_stack.get_label_height(row);
00199
00200 int collector_index = get_label_collector(row);
00201 GdkGC *gc = get_collector_gc(collector_index);
00202
00203 gdk_draw_rectangle(_pixmap, gc, TRUE,
00204 from_x, y - height + 2,
00205 to_x - from_x, height - 4);
00206 }
00207 }
00208
00209
00210
00211
00212
00213
00214
00215 void GtkStatsPianoRoll::
00216 end_draw() {
00217 gtk_widget_queue_draw(_graph_window);
00218 }
00219
00220
00221
00222
00223
00224
00225 void GtkStatsPianoRoll::
00226 idle() {
00227 if (_labels_changed) {
00228 update_labels();
00229 }
00230 }
00231
00232
00233
00234
00235
00236
00237
00238
00239 void GtkStatsPianoRoll::
00240 additional_graph_window_paint() {
00241 int num_user_guide_bars = get_num_user_guide_bars();
00242 for (int i = 0; i < num_user_guide_bars; i++) {
00243 draw_guide_bar(_graph_window->window, get_user_guide_bar(i));
00244 }
00245 }
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255 GtkStatsGraph::DragMode GtkStatsPianoRoll::
00256 consider_drag_start(int graph_x, int graph_y) {
00257 if (graph_y >= 0 && graph_y < get_ysize()) {
00258 if (graph_x >= 0 && graph_x < get_xsize()) {
00259
00260 int x = graph_x;
00261 double from_height = pixel_to_height(x - 2);
00262 double to_height = pixel_to_height(x + 2);
00263 _drag_guide_bar = find_user_guide_bar(from_height, to_height);
00264 if (_drag_guide_bar >= 0) {
00265 return DM_guide_bar;
00266 }
00267
00268 } else {
00269
00270
00271 return DM_new_guide_bar;
00272 }
00273 }
00274
00275 return GtkStatsGraph::consider_drag_start(graph_x, graph_y);
00276 }
00277
00278
00279
00280
00281
00282
00283
00284 gboolean GtkStatsPianoRoll::
00285 handle_button_press(GtkWidget *widget, int graph_x, int graph_y,
00286 bool double_click) {
00287 if (double_click) {
00288
00289
00290 clicked_label(get_collector_under_pixel(graph_x, graph_y));
00291 return TRUE;
00292 }
00293
00294 if (_potential_drag_mode == DM_none) {
00295 set_drag_mode(DM_scale);
00296 _drag_scale_start = pixel_to_height(graph_x);
00297
00298 return TRUE;
00299
00300 } else if (_potential_drag_mode == DM_guide_bar && _drag_guide_bar >= 0) {
00301 set_drag_mode(DM_guide_bar);
00302 _drag_start_x = graph_x;
00303
00304 return TRUE;
00305 }
00306
00307 return GtkStatsGraph::handle_button_press(widget, graph_x, graph_y,
00308 double_click);
00309 }
00310
00311
00312
00313
00314
00315
00316
00317 gboolean GtkStatsPianoRoll::
00318 handle_button_release(GtkWidget *widget, int graph_x, int graph_y) {
00319 if (_drag_mode == DM_scale) {
00320 set_drag_mode(DM_none);
00321
00322 return handle_motion(widget, graph_x, graph_y);
00323
00324 } else if (_drag_mode == DM_guide_bar) {
00325 if (graph_x < 0 || graph_x >= get_xsize()) {
00326 remove_user_guide_bar(_drag_guide_bar);
00327 } else {
00328 move_user_guide_bar(_drag_guide_bar, pixel_to_height(graph_x));
00329 }
00330 set_drag_mode(DM_none);
00331
00332 return handle_motion(widget, graph_x, graph_y);
00333 }
00334
00335 return GtkStatsGraph::handle_button_release(widget, graph_x, graph_y);
00336 }
00337
00338
00339
00340
00341
00342
00343
00344 gboolean GtkStatsPianoRoll::
00345 handle_motion(GtkWidget *widget, int graph_x, int graph_y) {
00346 if (_drag_mode == DM_none && _potential_drag_mode == DM_none) {
00347
00348 _label_stack.highlight_label(get_collector_under_pixel(graph_x, graph_y));
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362 } else {
00363
00364 _label_stack.highlight_label(-1);
00365 }
00366
00367 if (_drag_mode == DM_scale) {
00368 double ratio = (double)graph_x / (double)get_xsize();
00369 if (ratio > 0.0f) {
00370 set_horizontal_scale(_drag_scale_start / ratio);
00371 }
00372 return TRUE;
00373
00374 } else if (_drag_mode == DM_new_guide_bar) {
00375
00376
00377 if (graph_x >= 0 && graph_x < get_xsize()) {
00378 set_drag_mode(DM_guide_bar);
00379 _drag_guide_bar = add_user_guide_bar(pixel_to_height(graph_x));
00380 return TRUE;
00381 }
00382
00383 } else if (_drag_mode == DM_guide_bar) {
00384 move_user_guide_bar(_drag_guide_bar, pixel_to_height(graph_x));
00385 return TRUE;
00386 }
00387
00388 return GtkStatsGraph::handle_motion(widget, graph_x, graph_y);
00389 }
00390
00391
00392
00393
00394
00395
00396
00397 int GtkStatsPianoRoll::
00398 get_collector_under_pixel(int xpoint, int ypoint) {
00399 if (_label_stack.get_num_labels() == 0) {
00400 return -1;
00401 }
00402
00403
00404 int height = _label_stack.get_label_height(0);
00405 int row = (get_ysize() - ypoint) / height;
00406 if (row >= 0 && row < _label_stack.get_num_labels()) {
00407 return _label_stack.get_label_collector_index(row);
00408 } else {
00409 return -1;
00410 }
00411 }
00412
00413
00414
00415
00416
00417
00418 void GtkStatsPianoRoll::
00419 update_labels() {
00420 _label_stack.clear_labels();
00421 for (int i = 0; i < get_num_labels(); i++) {
00422 _label_stack.add_label(GtkStatsGraph::_monitor, this,
00423 _thread_index,
00424 get_label_collector(i), true);
00425 }
00426 _labels_changed = false;
00427 }
00428
00429
00430
00431
00432
00433
00434
00435 void GtkStatsPianoRoll::
00436 draw_guide_bar(GdkDrawable *surface, const PStatGraph::GuideBar &bar) {
00437 int x = height_to_pixel(bar._height);
00438
00439 if (x > 0 && x < get_xsize() - 1) {
00440
00441 switch (bar._style) {
00442 case GBS_target:
00443 gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_light_gray);
00444 break;
00445
00446 case GBS_user:
00447 gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_user_guide_bar);
00448 break;
00449
00450 case GBS_normal:
00451 gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_dark_gray);
00452 break;
00453 }
00454 gdk_draw_line(surface, _pixmap_gc, x, 0, x, get_ysize());
00455 }
00456 }
00457
00458
00459
00460
00461
00462
00463 void GtkStatsPianoRoll::
00464 draw_guide_labels() {
00465 int i;
00466 int num_guide_bars = get_num_guide_bars();
00467 for (i = 0; i < num_guide_bars; i++) {
00468 draw_guide_label(get_guide_bar(i));
00469 }
00470
00471 int num_user_guide_bars = get_num_user_guide_bars();
00472 for (i = 0; i < num_user_guide_bars; i++) {
00473 draw_guide_label(get_user_guide_bar(i));
00474 }
00475 }
00476
00477
00478
00479
00480
00481
00482
00483 void GtkStatsPianoRoll::
00484 draw_guide_label(const PStatGraph::GuideBar &bar) {
00485 GdkGC *gc = gdk_gc_new(_scale_area->window);
00486
00487 switch (bar._style) {
00488 case GBS_target:
00489 gdk_gc_set_rgb_fg_color(gc, &rgb_light_gray);
00490 break;
00491
00492 case GBS_user:
00493 gdk_gc_set_rgb_fg_color(gc, &rgb_user_guide_bar);
00494 break;
00495
00496 case GBS_normal:
00497 gdk_gc_set_rgb_fg_color(gc, &rgb_dark_gray);
00498 break;
00499 }
00500
00501 int x = height_to_pixel(bar._height);
00502 const string &label = bar._label;
00503
00504 PangoLayout *layout = gtk_widget_create_pango_layout(_window, label.c_str());
00505 int width, height;
00506 pango_layout_get_pixel_size(layout, &width, &height);
00507
00508 if (bar._style != GBS_user) {
00509 double from_height = pixel_to_height(x - width);
00510 double to_height = pixel_to_height(x + width);
00511 if (find_user_guide_bar(from_height, to_height) >= 0) {
00512
00513 g_object_unref(layout);
00514 g_object_unref(gc);
00515 return;
00516 }
00517 }
00518
00519 if (x >= 0 && x < get_xsize()) {
00520
00521 int junk_y;
00522
00523
00524 gtk_widget_translate_coordinates(_graph_window, _scale_area,
00525 x, 0,
00526 &x, &junk_y);
00527
00528 int this_x = x - width / 2;
00529 gdk_draw_layout(_scale_area->window, gc, this_x,
00530 _scale_area->allocation.height - height, layout);
00531 }
00532
00533 g_object_unref(layout);
00534 g_object_unref(gc);
00535 }
00536
00537
00538
00539
00540
00541
00542 gboolean GtkStatsPianoRoll::
00543 expose_event_callback(GtkWidget *widget, GdkEventExpose *event, gpointer data) {
00544 GtkStatsPianoRoll *self = (GtkStatsPianoRoll *)data;
00545 self->draw_guide_labels();
00546
00547 return TRUE;
00548 }