Panda3D
|
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 }