Panda3D
|
00001 // Filename: gtkStatsStripChart.cxx 00002 // Created by: drose (16Jan06) 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 "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 // Function: GtkStatsStripChart::Constructor 00025 // Access: Public 00026 // Description: 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 // If it's a level-type graph, show the appropriate units. 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 // If it's a time-type graph, show the ms/Hz units. 00051 set_guide_bar_units(get_guide_bar_units() | GBU_show_units); 00052 } 00053 00054 // Put some stuff on top of the graph. 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 // Add a DrawingArea widget to the right of the graph, to display 00070 // all of the scale units. 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 // Allow the window to be resized as small as the user likes. We 00086 // have to do this after the window has been shown; otherwise, it 00087 // will affect the window's initial size. 00088 gtk_widget_set_size_request(_window, 0, 0); 00089 00090 clear_region(); 00091 } 00092 00093 //////////////////////////////////////////////////////////////////// 00094 // Function: GtkStatsStripChart::Destructor 00095 // Access: Public, Virtual 00096 // Description: 00097 //////////////////////////////////////////////////////////////////// 00098 GtkStatsStripChart:: 00099 ~GtkStatsStripChart() { 00100 } 00101 00102 //////////////////////////////////////////////////////////////////// 00103 // Function: GtkStatsStripChart::new_collector 00104 // Access: Public, Virtual 00105 // Description: Called whenever a new Collector definition is 00106 // received from the client. 00107 //////////////////////////////////////////////////////////////////// 00108 void GtkStatsStripChart:: 00109 new_collector(int collector_index) { 00110 GtkStatsGraph::new_collector(collector_index); 00111 } 00112 00113 //////////////////////////////////////////////////////////////////// 00114 // Function: GtkStatsStripChart::new_data 00115 // Access: Public, Virtual 00116 // Description: Called as each frame's data is made available. There 00117 // is no gurantee the frames will arrive in order, or 00118 // that all of them will arrive at all. The monitor 00119 // should be prepared to accept frames received 00120 // out-of-order or missing. 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 // Function: GtkStatsStripChart::force_redraw 00144 // Access: Public, Virtual 00145 // Description: Called when it is necessary to redraw the entire graph. 00146 //////////////////////////////////////////////////////////////////// 00147 void GtkStatsStripChart:: 00148 force_redraw() { 00149 PStatStripChart::force_redraw(); 00150 } 00151 00152 //////////////////////////////////////////////////////////////////// 00153 // Function: GtkStatsStripChart::changed_graph_size 00154 // Access: Public, Virtual 00155 // Description: Called when the user has resized the window, forcing 00156 // a resize of the graph. 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 // Function: GtkStatsStripChart::set_time_units 00165 // Access: Public, Virtual 00166 // Description: Called when the user selects a new time units from 00167 // the monitor pulldown menu, this should adjust the 00168 // units for the graph to the indicated mask if it is a 00169 // time-based graph. 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 // Function: GtkStatsStripChart::set_scroll_speed 00185 // Access: Public 00186 // Description: Called when the user selects a new scroll speed from 00187 // the monitor pulldown menu, this should adjust the 00188 // speed for the graph to the indicated value. 00189 //////////////////////////////////////////////////////////////////// 00190 void GtkStatsStripChart:: 00191 set_scroll_speed(double scroll_speed) { 00192 // The speed factor indicates chart widths per minute. 00193 if (scroll_speed != 0.0f) { 00194 set_horizontal_scale(60.0f / scroll_speed); 00195 } 00196 } 00197 00198 //////////////////////////////////////////////////////////////////// 00199 // Function: GtkStatsStripChart::clicked_label 00200 // Access: Public, Virtual 00201 // Description: Called when the user single-clicks on a label. 00202 //////////////////////////////////////////////////////////////////// 00203 void GtkStatsStripChart:: 00204 clicked_label(int collector_index) { 00205 if (collector_index < 0) { 00206 // Clicking on whitespace in the graph is the same as clicking on 00207 // the top label. 00208 collector_index = get_collector_index(); 00209 } 00210 00211 if (collector_index == get_collector_index() && collector_index != 0) { 00212 // Clicking on the top label means to go up to the parent level. 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 // Unless the parent is "Frame", and we're not a time collector. 00220 } else { 00221 set_collector_index(def._parent_index); 00222 } 00223 } 00224 00225 } else { 00226 // Clicking on any other label means to focus on that. 00227 set_collector_index(collector_index); 00228 } 00229 } 00230 00231 //////////////////////////////////////////////////////////////////// 00232 // Function: GtkStatsStripChart::set_vertical_scale 00233 // Access: Public 00234 // Description: Changes the value the height of the vertical axis 00235 // represents. This may force a redraw. 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 // Function: GtkStatsStripChart::update_labels 00247 // Access: Protected, Virtual 00248 // Description: Resets the list of labels. 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 // Function: GtkStatsStripChart::clear_region 00264 // Access: Protected, Virtual 00265 // Description: Erases the chart area. 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 // Function: GtkStatsStripChart::copy_region 00276 // Access: Protected, Virtual 00277 // Description: Should be overridden by the user class to copy a 00278 // region of the chart from one part of the chart to 00279 // another. This is used to implement scrolling. 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 // Also shift the brush origin over, so we still get proper 00288 // dithering. 00289 _brush_origin += (dest_x - start_x); 00290 // SetBrushOrgEx(_bitmap_dc, _brush_origin, 0, NULL); 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 // Function: GtkStatsStripChart::draw_slice 00300 // Access: Protected, Virtual 00301 // Description: Draws a single vertical slice of the strip chart, at 00302 // the given pixel position, and corresponding to the 00303 // indicated level data. 00304 //////////////////////////////////////////////////////////////////// 00305 void GtkStatsStripChart:: 00306 draw_slice(int x, int w, const PStatStripChart::FrameData &fdata) { 00307 // Start by clearing the band first. 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 // Off the top. Go ahead and clamp it by hand, in case it's so 00323 // far off the top we'd overflow the 16-bit pixel value. 00324 gdk_draw_rectangle(_pixmap, gc, TRUE, x, 0, w, y); 00325 // And we can consider ourselves done now. 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 // Function: GtkStatsStripChart::draw_empty 00337 // Access: Protected, Virtual 00338 // Description: Draws a single vertical slice of background color. 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 // Function: GtkStatsStripChart::draw_cursor 00349 // Access: Protected, Virtual 00350 // Description: Draws a single vertical slice of foreground color. 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 // Function: GtkStatsStripChart::end_draw 00360 // Access: Protected, Virtual 00361 // Description: Should be overridden by the user class. This hook 00362 // will be called after drawing a series of color bars 00363 // in the strip chart; it gives the pixel range that 00364 // was just redrawn. 00365 //////////////////////////////////////////////////////////////////// 00366 void GtkStatsStripChart:: 00367 end_draw(int from_x, int to_x) { 00368 // Draw in the guide bars. 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 // Function: GtkStatsStripChart::additional_graph_window_paint 00382 // Access: Protected, Virtual 00383 // Description: This is called during the servicing of expose_event; 00384 // it gives a derived class opportunity to do some 00385 // further painting into the graph window. 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 // Function: GtkStatsStripChart::consider_drag_start 00397 // Access: Protected, Virtual 00398 // Description: Based on the mouse position within the graph window, 00399 // look for draggable things the mouse might be hovering 00400 // over and return the appropriate DragMode enum or 00401 // DM_none if nothing is indicated. 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 // See if the mouse is over a user-defined guide bar. 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 // The mouse is above or below the graph; maybe create a new 00418 // guide bar. 00419 return DM_new_guide_bar; 00420 } 00421 } 00422 00423 return GtkStatsGraph::consider_drag_start(graph_x, graph_y); 00424 } 00425 00426 //////////////////////////////////////////////////////////////////// 00427 // Function: GtkStatsStripChart::set_drag_mode 00428 // Access: Protected, Virtual 00429 // Description: This should be called whenever the drag mode needs to 00430 // change state. It provides hooks for a derived class 00431 // to do something special. 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 // Disable smoothing for these expensive operations. 00441 set_average_mode(false); 00442 break; 00443 00444 default: 00445 // Restore smoothing according to the current setting of the check 00446 // box. 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 // Function: GtkStatsStripChart::handle_button_press 00456 // Access: Protected, Virtual 00457 // Description: Called when the mouse button is depressed within the 00458 // graph window. 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 // Double-clicking on a color bar in the graph is the same as 00465 // double-clicking on the corresponding label. 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 //SetCapture(_graph_window); 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 //SetCapture(_graph_window); 00480 return TRUE; 00481 } 00482 00483 return GtkStatsGraph::handle_button_press(widget, graph_x, graph_y, 00484 double_click); 00485 } 00486 00487 //////////////////////////////////////////////////////////////////// 00488 // Function: GtkStatsStripChart::handle_button_release 00489 // Access: Protected, Virtual 00490 // Description: Called when the mouse button is released within the 00491 // graph window. 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 //ReleaseCapture(); 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 //ReleaseCapture(); 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 // Function: GtkStatsStripChart::ns_motion_notify_event_callback 00516 // Access: Protected, Virtual 00517 // Description: Called when the mouse is moved within the 00518 // graph window. 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 // When the mouse is over a color bar, highlight it. 00524 _label_stack.highlight_label(get_collector_under_pixel(graph_x, graph_y)); 00525 00526 /* 00527 // Now we want to get a WM_MOUSELEAVE when the mouse leaves the 00528 // graph window. 00529 TRACKMOUSEEVENT tme = { 00530 sizeof(TRACKMOUSEEVENT), 00531 TME_LEAVE, 00532 _graph_window, 00533 0 00534 }; 00535 TrackMouseEvent(&tme); 00536 */ 00537 00538 } else { 00539 // If the mouse is in some drag mode, stop highlighting. 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 // We haven't created the new guide bar yet; we won't until the 00552 // mouse comes within the graph's region. 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 // Function: GtkStatsStripChart::draw_guide_bar 00569 // Access: Private 00570 // Description: Draws the line for the indicated guide bar on the 00571 // graph. 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 // Only draw it if it's not too close to the top. 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 // Function: GtkStatsStripChart::draw_guide_labels 00599 // Access: Private 00600 // Description: This is called during the servicing of expose_event. 00601 //////////////////////////////////////////////////////////////////// 00602 void GtkStatsStripChart:: 00603 draw_guide_labels() { 00604 // Draw in the labels for the guide bars. 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 // Function: GtkStatsStripChart::draw_guide_label 00625 // Access: Private 00626 // Description: Draws the text for the indicated guide bar label to 00627 // the right of the graph, unless it would overlap with 00628 // the indicated last label, whose top pixel value is 00629 // given. Returns the top pixel value of the new label. 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 // Omit the label: there's a user-defined guide bar in the same space. 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 // Now convert our y to a coordinate within our drawing area. 00669 int junk_x; 00670 00671 // The y coordinate comes from the graph_window. 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 // Function: GtkStatsStripChart::toggled_callback 00690 // Access: Private, Static 00691 // Description: Called when the smooth check box is toggled. 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 // Function: GtkStatsStripChart::expose_event_callback 00703 // Access: Private, Static 00704 // Description: Draws in the scale labels. 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 }