Panda3D

gtkStatsStripChart.cxx

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 }
 All Classes Functions Variables Enumerations