Panda3D

gtkStatsGraph.cxx

00001 // Filename: gtkStatsGraph.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 "gtkStatsGraph.h"
00016 #include "gtkStatsMonitor.h"
00017 #include "gtkStatsLabelStack.h"
00018 
00019 const GdkColor GtkStatsGraph::rgb_white = {
00020   0, 0xffff, 0xffff, 0xffff
00021 };
00022 const GdkColor GtkStatsGraph::rgb_light_gray = {
00023   0, 0x9a9a, 0x9a9a, 0x9a9a,
00024 };
00025 const GdkColor GtkStatsGraph::rgb_dark_gray = {
00026   0, 0x3333, 0x3333, 0x3333,
00027 };
00028 const GdkColor GtkStatsGraph::rgb_black = {
00029   0, 0x0000, 0x0000, 0x0000
00030 };
00031 const GdkColor GtkStatsGraph::rgb_user_guide_bar = {
00032   0, 0x8282, 0x9696, 0xffff
00033 };
00034 
00035 ////////////////////////////////////////////////////////////////////
00036 //     Function: GtkStatsGraph::Constructor
00037 //       Access: Public
00038 //  Description:
00039 ////////////////////////////////////////////////////////////////////
00040 GtkStatsGraph::
00041 GtkStatsGraph(GtkStatsMonitor *monitor) :
00042   _monitor(monitor)
00043 {
00044   _parent_window = NULL;
00045   _window = NULL;
00046   _graph_window = NULL;
00047   _scale_area = NULL;
00048 
00049   GtkWidget *parent_window = monitor->get_window();
00050 
00051   GdkDisplay *display = gdk_drawable_get_display(parent_window->window);
00052   _hand_cursor = gdk_cursor_new_for_display(display, GDK_HAND2);
00053 
00054   _pixmap = 0;
00055   _pixmap_gc = 0;
00056 
00057   _pixmap_xsize = 0;
00058   _pixmap_ysize = 0;
00059 
00060   _window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
00061 
00062   // These calls were intended to kind of emulate the Windows MDI
00063   // behavior, but it's just weird.
00064   // gtk_window_set_transient_for(GTK_WINDOW(_window), GTK_WINDOW(parent_window));
00065   // gtk_window_set_destroy_with_parent(GTK_WINDOW(_window), TRUE);
00066 
00067   gtk_widget_add_events(_window, 
00068       GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
00069       GDK_POINTER_MOTION_MASK);
00070   g_signal_connect(G_OBJECT(_window), "delete_event",
00071        G_CALLBACK(window_delete_event), this);
00072   g_signal_connect(G_OBJECT(_window), "destroy",
00073        G_CALLBACK(window_destroy), this);
00074   g_signal_connect(G_OBJECT(_window), "button_press_event",  
00075        G_CALLBACK(button_press_event_callback), this);
00076   g_signal_connect(G_OBJECT(_window), "button_release_event",  
00077        G_CALLBACK(button_release_event_callback), this);
00078   g_signal_connect(G_OBJECT(_window), "motion_notify_event",  
00079        G_CALLBACK(motion_notify_event_callback), this);
00080 
00081   _graph_window = gtk_drawing_area_new();
00082   gtk_widget_add_events(_graph_window, 
00083       GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
00084       GDK_POINTER_MOTION_MASK);
00085   g_signal_connect(G_OBJECT(_graph_window), "expose_event",  
00086        G_CALLBACK(graph_expose_callback), this);
00087   g_signal_connect(G_OBJECT(_graph_window), "configure_event",  
00088        G_CALLBACK(configure_graph_callback), this);
00089   g_signal_connect(G_OBJECT(_graph_window), "button_press_event",  
00090        G_CALLBACK(button_press_event_callback), this);
00091   g_signal_connect(G_OBJECT(_graph_window), "button_release_event",  
00092        G_CALLBACK(button_release_event_callback), this);
00093   g_signal_connect(G_OBJECT(_graph_window), "motion_notify_event",  
00094        G_CALLBACK(motion_notify_event_callback), this);
00095 
00096   // A Frame to hold the graph.
00097   GtkWidget *graph_frame = gtk_frame_new(NULL);
00098   gtk_frame_set_shadow_type(GTK_FRAME(graph_frame), GTK_SHADOW_IN);
00099   gtk_container_add(GTK_CONTAINER(graph_frame), _graph_window);
00100 
00101   // A VBox to hold the graph's frame, and any numbers (scale legend?
00102   // total?) above it.
00103   _graph_vbox = gtk_vbox_new(FALSE, 0);
00104   gtk_box_pack_end(GTK_BOX(_graph_vbox), graph_frame,
00105        TRUE, TRUE, 0);
00106 
00107   // An HBox to hold the graph's frame, and the scale legend to the
00108   // right of it.
00109   _graph_hbox = gtk_hbox_new(FALSE, 0);
00110   gtk_box_pack_start(GTK_BOX(_graph_hbox), _graph_vbox,
00111          TRUE, TRUE, 0);
00112 
00113   // An HPaned to hold the label stack and the graph hbox.
00114   _hpaned = gtk_hpaned_new();
00115   gtk_container_add(GTK_CONTAINER(_window), _hpaned);
00116   gtk_container_set_border_width(GTK_CONTAINER(_window), 8);
00117 
00118   gtk_paned_pack1(GTK_PANED(_hpaned), _label_stack.get_widget(), TRUE, TRUE);
00119   gtk_paned_pack2(GTK_PANED(_hpaned), _graph_hbox, TRUE, TRUE);
00120 
00121   _drag_mode = DM_none;
00122   _potential_drag_mode = DM_none;
00123   _drag_scale_start = 0.0f;
00124 
00125   _pause = false;
00126 }
00127 
00128 ////////////////////////////////////////////////////////////////////
00129 //     Function: GtkStatsGraph::Destructor
00130 //       Access: Public, Virtual
00131 //  Description:
00132 ////////////////////////////////////////////////////////////////////
00133 GtkStatsGraph::
00134 ~GtkStatsGraph() {
00135   _monitor = (GtkStatsMonitor *)NULL;
00136   release_pixmap();
00137   
00138   Brushes::iterator bi;
00139   for (bi = _brushes.begin(); bi != _brushes.end(); ++bi) {
00140     GdkGC *gc = (*bi).second;
00141     g_object_unref(gc);
00142   }
00143 
00144   _label_stack.clear_labels();
00145 
00146   if (_window != (GtkWidget *)NULL) {
00147     GtkWidget *window = _window;
00148     _window = NULL;
00149     gtk_widget_destroy(window);
00150   }
00151 }
00152 
00153 ////////////////////////////////////////////////////////////////////
00154 //     Function: GtkStatsGraph::new_collector
00155 //       Access: Public, Virtual
00156 //  Description: Called whenever a new Collector definition is
00157 //               received from the client.
00158 ////////////////////////////////////////////////////////////////////
00159 void GtkStatsGraph::
00160 new_collector(int new_collector) {
00161 }
00162 
00163 ////////////////////////////////////////////////////////////////////
00164 //     Function: GtkStatsGraph::new_data
00165 //       Access: Public, Virtual
00166 //  Description: Called whenever new data arrives.
00167 ////////////////////////////////////////////////////////////////////
00168 void GtkStatsGraph::
00169 new_data(int thread_index, int frame_number) {
00170 }
00171 
00172 ////////////////////////////////////////////////////////////////////
00173 //     Function: GtkStatsGraph::force_redraw
00174 //       Access: Public, Virtual
00175 //  Description: Called when it is necessary to redraw the entire graph.
00176 ////////////////////////////////////////////////////////////////////
00177 void GtkStatsGraph::
00178 force_redraw() {
00179 }
00180 
00181 ////////////////////////////////////////////////////////////////////
00182 //     Function: GtkStatsGraph::changed_graph_size
00183 //       Access: Public, Virtual
00184 //  Description: Called when the user has resized the window, forcing
00185 //               a resize of the graph.
00186 ////////////////////////////////////////////////////////////////////
00187 void GtkStatsGraph::
00188 changed_graph_size(int graph_xsize, int graph_ysize) {
00189 }
00190 
00191 ////////////////////////////////////////////////////////////////////
00192 //     Function: GtkStatsGraph::set_time_units
00193 //       Access: Public, Virtual
00194 //  Description: Called when the user selects a new time units from
00195 //               the monitor pulldown menu, this should adjust the
00196 //               units for the graph to the indicated mask if it is a
00197 //               time-based graph.
00198 ////////////////////////////////////////////////////////////////////
00199 void GtkStatsGraph::
00200 set_time_units(int unit_mask) {
00201 }
00202 
00203 ////////////////////////////////////////////////////////////////////
00204 //     Function: GtkStatsGraph::set_scroll_speed
00205 //       Access: Public
00206 //  Description: Called when the user selects a new scroll speed from
00207 //               the monitor pulldown menu, this should adjust the
00208 //               speed for the graph to the indicated value.
00209 ////////////////////////////////////////////////////////////////////
00210 void GtkStatsGraph::
00211 set_scroll_speed(double scroll_speed) {
00212 }
00213 
00214 ////////////////////////////////////////////////////////////////////
00215 //     Function: GtkStatsGraph::set_pause
00216 //       Access: Public
00217 //  Description: Changes the pause flag for the graph.  When this flag
00218 //               is true, the graph does not update in response to new
00219 //               data.
00220 ////////////////////////////////////////////////////////////////////
00221 void GtkStatsGraph::
00222 set_pause(bool pause) {
00223   _pause = pause;
00224 }
00225 
00226 ////////////////////////////////////////////////////////////////////
00227 //     Function: GtkStatsGraph::user_guide_bars_changed
00228 //       Access: Public
00229 //  Description: Called when the user guide bars have been changed.
00230 ////////////////////////////////////////////////////////////////////
00231 void GtkStatsGraph::
00232 user_guide_bars_changed() {
00233   if (_scale_area != NULL) {
00234     gtk_widget_queue_draw(_scale_area);
00235   }
00236   gtk_widget_queue_draw(_graph_window);
00237 }
00238 
00239 ////////////////////////////////////////////////////////////////////
00240 //     Function: GtkStatsGraph::clicked_label
00241 //       Access: Public, Virtual
00242 //  Description: Called when the user single-clicks on a label.
00243 ////////////////////////////////////////////////////////////////////
00244 void GtkStatsGraph::
00245 clicked_label(int collector_index) {
00246 }
00247 
00248 ////////////////////////////////////////////////////////////////////
00249 //     Function: GtkStatsGraph::close
00250 //       Access: Protected
00251 //  Description: Should be called when the user closes the associated
00252 //               window.  This tells the monitor to remove the graph.
00253 ////////////////////////////////////////////////////////////////////
00254 void GtkStatsGraph::
00255 close() {
00256   _label_stack.clear_labels(false);
00257   if (_window != (GtkWidget *)NULL) {
00258     _window = NULL;
00259 
00260     GtkStatsMonitor *monitor = _monitor;
00261     _monitor = (GtkStatsMonitor *)NULL;
00262     if (monitor != (GtkStatsMonitor *)NULL) {
00263       monitor->remove_graph(this);
00264     }
00265   }
00266 }
00267 
00268 ////////////////////////////////////////////////////////////////////
00269 //     Function: GtkStatsGraph::get_collector_gc
00270 //       Access: Protected
00271 //  Description: Returns a GC suitable for drawing in the indicated
00272 //               collector's color.
00273 ////////////////////////////////////////////////////////////////////
00274 GdkGC *GtkStatsGraph::
00275 get_collector_gc(int collector_index) {
00276   Brushes::iterator bi;
00277   bi = _brushes.find(collector_index);
00278   if (bi != _brushes.end()) {
00279     return (*bi).second;
00280   }
00281 
00282   // Ask the monitor what color this guy should be.
00283   LRGBColor rgb = _monitor->get_collector_color(collector_index);
00284 
00285   GdkColor c;
00286   c.red = (int)(rgb[0] * 65535.0f);
00287   c.green = (int)(rgb[1] * 65535.0f);
00288   c.blue = (int)(rgb[2] * 65535.0f);
00289   GdkGC *gc = gdk_gc_new(_pixmap);
00290   //  g_object_ref(gc);  // Should this be ref_sink?
00291   gdk_gc_set_rgb_fg_color(gc, &c);
00292 
00293   _brushes[collector_index] = gc;
00294   return gc;
00295 }
00296 
00297 ////////////////////////////////////////////////////////////////////
00298 //     Function: GtkStatsGraph::additional_graph_window_paint
00299 //       Access: Protected, Virtual
00300 //  Description: This is called during the servicing of expose_event;
00301 //               it gives a derived class opportunity to do some
00302 //               further painting into the graph window.
00303 ////////////////////////////////////////////////////////////////////
00304 void GtkStatsGraph::
00305 additional_graph_window_paint() {
00306 }
00307 
00308 ////////////////////////////////////////////////////////////////////
00309 //     Function: GtkStatsGraph::consider_drag_start
00310 //       Access: Protected, Virtual
00311 //  Description: Based on the mouse position within the graph window,
00312 //               look for draggable things the mouse might be hovering
00313 //               over and return the appropriate DragMode enum or
00314 //               DM_none if nothing is indicated.
00315 ////////////////////////////////////////////////////////////////////
00316 GtkStatsGraph::DragMode GtkStatsGraph::
00317 consider_drag_start(int graph_x, int graph_y) {
00318   return DM_none;
00319 }
00320 
00321 ////////////////////////////////////////////////////////////////////
00322 //     Function: GtkStatsGraph::set_drag_mode
00323 //       Access: Protected, Virtual
00324 //  Description: This should be called whenever the drag mode needs to
00325 //               change state.  It provides hooks for a derived class
00326 //               to do something special.
00327 ////////////////////////////////////////////////////////////////////
00328 void GtkStatsGraph::
00329 set_drag_mode(GtkStatsGraph::DragMode drag_mode) {
00330   _drag_mode = drag_mode;
00331 }
00332 
00333 ////////////////////////////////////////////////////////////////////
00334 //     Function: GtkStatsGraph::handle_button_press
00335 //       Access: Protected, Virtual
00336 //  Description: Called when the mouse button is depressed within the
00337 //               window, or any nested window.
00338 ////////////////////////////////////////////////////////////////////
00339 gboolean GtkStatsGraph::
00340 handle_button_press(GtkWidget *widget, int graph_x, int graph_y,
00341         bool double_click) {
00342   if (_potential_drag_mode != DM_none) {
00343     set_drag_mode(_potential_drag_mode);
00344     _drag_start_x = graph_x;
00345     _drag_start_y = graph_y;
00346     //    SetCapture(_window);
00347   }
00348   return TRUE;
00349 }
00350 
00351 ////////////////////////////////////////////////////////////////////
00352 //     Function: GtkStatsGraph::handle_button_release
00353 //       Access: Protected, Virtual
00354 //  Description: Called when the mouse button is released within the
00355 //               window, or any nested window.
00356 ////////////////////////////////////////////////////////////////////
00357 gboolean GtkStatsGraph::
00358 handle_button_release(GtkWidget *widget, int graph_x, int graph_y) {
00359   set_drag_mode(DM_none);
00360   //  ReleaseCapture();
00361 
00362   return handle_motion(widget, graph_x, graph_y);
00363 }
00364 
00365 ////////////////////////////////////////////////////////////////////
00366 //     Function: GtkStatsGraph::handle_motion
00367 //       Access: Protected, Virtual, Static
00368 //  Description: Called when the mouse is moved within the
00369 //               window, or any nested window.
00370 ////////////////////////////////////////////////////////////////////
00371 gboolean GtkStatsGraph::
00372 handle_motion(GtkWidget *widget, int graph_x, int graph_y) {
00373   _potential_drag_mode = consider_drag_start(graph_x, graph_y);
00374 
00375   if (_potential_drag_mode == DM_guide_bar ||
00376       _drag_mode == DM_guide_bar) {
00377     gdk_window_set_cursor(_window->window, _hand_cursor);
00378 
00379   } else {
00380     gdk_window_set_cursor(_window->window, NULL);
00381   }
00382 
00383   return TRUE;
00384 }
00385 
00386 ////////////////////////////////////////////////////////////////////
00387 //     Function: GtkStatsGraph::setup_pixmap
00388 //       Access: Private
00389 //  Description: Sets up a backing-store bitmap of the indicated size.
00390 ////////////////////////////////////////////////////////////////////
00391 void GtkStatsGraph::
00392 setup_pixmap(int xsize, int ysize) {
00393   release_pixmap();
00394 
00395   _pixmap_xsize = max(xsize, 0);
00396   _pixmap_ysize = max(ysize, 0);
00397 
00398   _pixmap = gdk_pixmap_new(_graph_window->window, _pixmap_xsize, _pixmap_ysize, -1);
00399   //  g_object_ref(_pixmap);  // Should this be ref_sink?
00400   _pixmap_gc = gdk_gc_new(_pixmap);
00401   //  g_object_ref(_pixmap_gc);   // Should this be ref_sink?
00402 
00403   gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_white);
00404   gdk_draw_rectangle(_pixmap, _pixmap_gc, TRUE, 0, 0, 
00405          _pixmap_xsize, _pixmap_ysize);
00406 }
00407 
00408 ////////////////////////////////////////////////////////////////////
00409 //     Function: GtkStatsGraph::release_pixmap
00410 //       Access: Private
00411 //  Description: Frees the backing-store bitmap created by
00412 //               setup_pixmap().
00413 ////////////////////////////////////////////////////////////////////
00414 void GtkStatsGraph::
00415 release_pixmap() {
00416   if (_pixmap != NULL) {
00417     g_object_unref(_pixmap);
00418     g_object_unref(_pixmap_gc);
00419   }
00420 }
00421 
00422 ////////////////////////////////////////////////////////////////////
00423 //     Function: GtkStatsGraph::window_delete_event
00424 //       Access: Private, Static
00425 //  Description: Callback when the window is closed by the user.
00426 ////////////////////////////////////////////////////////////////////
00427 gboolean GtkStatsGraph::
00428 window_delete_event(GtkWidget *widget, GdkEvent *event, gpointer data) {
00429   // Returning FALSE to indicate we should destroy the window
00430   // when the user selects "close".
00431   return FALSE;
00432 }
00433 
00434 ////////////////////////////////////////////////////////////////////
00435 //     Function: GtkStatsGraph::window_destroy
00436 //       Access: Private, Static
00437 //  Description: Callback when the window is destroyed by the system
00438 //               (or by delete_event).
00439 ////////////////////////////////////////////////////////////////////
00440 void GtkStatsGraph::
00441 window_destroy(GtkWidget *widget, gpointer data) {
00442   GtkStatsGraph *self = (GtkStatsGraph *)data;
00443   self->close();
00444 }
00445 
00446 ////////////////////////////////////////////////////////////////////
00447 //     Function: GtkStatsGraph::graph_expose_callback
00448 //       Access: Private, Static
00449 //  Description: Fills in the graph window.
00450 ////////////////////////////////////////////////////////////////////
00451 gboolean GtkStatsGraph::
00452 graph_expose_callback(GtkWidget *widget, GdkEventExpose *event, gpointer data) {
00453   GtkStatsGraph *self = (GtkStatsGraph *)data;
00454 
00455   if (self->_pixmap != NULL) {
00456     gdk_draw_drawable(self->_graph_window->window, 
00457           self->_graph_window->style->fg_gc[0],
00458           self->_pixmap, 0, 0, 0, 0,
00459           self->_pixmap_xsize, self->_pixmap_ysize);
00460   }
00461 
00462   self->additional_graph_window_paint();
00463     
00464   return TRUE;
00465 }
00466 
00467 ////////////////////////////////////////////////////////////////////
00468 //     Function: GtkStatsGraph::configure_graph_callback
00469 //       Access: Private, Static
00470 //  Description: Changes the size of the graph window
00471 ////////////////////////////////////////////////////////////////////
00472 gboolean GtkStatsGraph::
00473 configure_graph_callback(GtkWidget *widget, GdkEventConfigure *event, 
00474        gpointer data) {
00475   GtkStatsGraph *self = (GtkStatsGraph *)data;
00476 
00477   self->changed_graph_size(event->width, event->height);
00478   self->setup_pixmap(event->width, event->height);
00479   self->force_redraw();
00480     
00481   return TRUE;
00482 }
00483 
00484 ////////////////////////////////////////////////////////////////////
00485 //     Function: GtkStatsGraph::button_press_event_callback
00486 //       Access: Private, Static
00487 //  Description: Called when the mouse button is depressed within the
00488 //               graph window or main window.
00489 ////////////////////////////////////////////////////////////////////
00490 gboolean GtkStatsGraph::
00491 button_press_event_callback(GtkWidget *widget, GdkEventButton *event, 
00492           gpointer data) {
00493   GtkStatsGraph *self = (GtkStatsGraph *)data;
00494   int graph_x, graph_y;
00495   gtk_widget_translate_coordinates(widget, self->_graph_window,
00496            (int)event->x, (int)event->y,
00497            &graph_x, &graph_y);
00498 
00499   bool double_click = (event->type == GDK_2BUTTON_PRESS);
00500 
00501   return self->handle_button_press(widget, graph_x, graph_y, double_click);
00502 }
00503 
00504 ////////////////////////////////////////////////////////////////////
00505 //     Function: GtkStatsGraph::button_release_event_callback
00506 //       Access: Private, Static
00507 //  Description: Called when the mouse button is released within the
00508 //               graph window or main window.
00509 ////////////////////////////////////////////////////////////////////
00510 gboolean GtkStatsGraph::
00511 button_release_event_callback(GtkWidget *widget, GdkEventButton *event, 
00512             gpointer data) {
00513   GtkStatsGraph *self = (GtkStatsGraph *)data;
00514   int graph_x, graph_y;
00515   gtk_widget_translate_coordinates(widget, self->_graph_window,
00516            (int)event->x, (int)event->y,
00517            &graph_x, &graph_y);
00518 
00519   return self->handle_button_release(widget, graph_x, graph_y);
00520 }
00521 
00522 ////////////////////////////////////////////////////////////////////
00523 //     Function: GtkStatsGraph::motion_notify_event_callback
00524 //       Access: Private, Static
00525 //  Description: Called when the mouse is moved within the
00526 //               graph window or main window.
00527 ////////////////////////////////////////////////////////////////////
00528 gboolean GtkStatsGraph::
00529 motion_notify_event_callback(GtkWidget *widget, GdkEventMotion *event, 
00530            gpointer data) {
00531   GtkStatsGraph *self = (GtkStatsGraph *)data;
00532   int graph_x, graph_y;
00533   gtk_widget_translate_coordinates(widget, self->_graph_window,
00534            (int)event->x, (int)event->y,
00535            &graph_x, &graph_y);
00536 
00537   return self->handle_motion(widget, graph_x, graph_y);
00538 }
 All Classes Functions Variables Enumerations