Panda3D

gtkStatsChartMenu.cxx

00001 // Filename: gtkStatsChartMenu.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 "gtkStatsChartMenu.h"
00016 #include "gtkStatsMonitor.h"
00017 
00018 ////////////////////////////////////////////////////////////////////
00019 //     Function: GtkStatsChartMenu::Constructor
00020 //       Access: Public
00021 //  Description:
00022 ////////////////////////////////////////////////////////////////////
00023 GtkStatsChartMenu::
00024 GtkStatsChartMenu(GtkStatsMonitor *monitor, int thread_index) :
00025   _monitor(monitor),
00026   _thread_index(thread_index)
00027 {
00028   _menu = gtk_menu_new();
00029   gtk_widget_show(_menu);
00030   do_update();
00031 }
00032 
00033 ////////////////////////////////////////////////////////////////////
00034 //     Function: GtkStatsChartMenu::Destructor
00035 //       Access: Public
00036 //  Description:
00037 ////////////////////////////////////////////////////////////////////
00038 GtkStatsChartMenu::
00039 ~GtkStatsChartMenu() {
00040 }
00041 
00042 ////////////////////////////////////////////////////////////////////
00043 //     Function: GtkStatsChartMenu::get_menu_widget
00044 //       Access: Public
00045 //  Description: Returns the gtk widget for this particular
00046 //               menu.
00047 ////////////////////////////////////////////////////////////////////
00048 GtkWidget *GtkStatsChartMenu::
00049 get_menu_widget() {
00050   return _menu;
00051 }
00052 
00053 ////////////////////////////////////////////////////////////////////
00054 //     Function: GtkStatsChartMenu::add_to_menu_bar
00055 //       Access: Public
00056 //  Description: Adds the menu to the end of the indicated menu bar.
00057 ////////////////////////////////////////////////////////////////////
00058 void GtkStatsChartMenu::
00059 add_to_menu_bar(GtkWidget *menu_bar, int position) {
00060   const PStatClientData *client_data = _monitor->get_client_data();
00061   string thread_name;
00062   if (_thread_index == 0) {
00063     // A special case for the main thread.
00064     thread_name = "Graphs";
00065   } else {
00066     thread_name = client_data->get_thread_name(_thread_index);
00067   }
00068 
00069   GtkWidget *menu_item = gtk_menu_item_new_with_label(thread_name.c_str());
00070   gtk_widget_show(menu_item);
00071   gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), _menu);
00072 
00073   gtk_menu_shell_insert(GTK_MENU_SHELL(menu_bar), menu_item, position);
00074 }
00075 
00076 ////////////////////////////////////////////////////////////////////
00077 //     Function: GtkStatsChartMenu::check_update
00078 //       Access: Public
00079 //  Description: Checks to see if the menu needs to be updated
00080 //               (e.g. because of new data from the client), and
00081 //               updates it if necessary.
00082 ////////////////////////////////////////////////////////////////////
00083 void GtkStatsChartMenu::
00084 check_update() {
00085   PStatView &view = _monitor->get_view(_thread_index);
00086   if (view.get_level_index() != _last_level_index) {
00087     do_update();
00088   }
00089 }
00090  
00091 ////////////////////////////////////////////////////////////////////
00092 //     Function: GtkStatsChartMenu::do_update
00093 //       Access: Public
00094 //  Description: Unconditionally updates the menu with the latest data
00095 //               from the client.
00096 ////////////////////////////////////////////////////////////////////
00097 void GtkStatsChartMenu::
00098 do_update() {
00099   PStatView &view = _monitor->get_view(_thread_index);
00100   _last_level_index = view.get_level_index();
00101 
00102   // First, remove all of the old entries from the menu.
00103   gtk_container_foreach(GTK_CONTAINER(_menu), remove_menu_child, _menu);
00104 
00105   // Now rebuild the menu with the new set of entries.
00106 
00107   // The menu item(s) for the thread's frame time goes first.
00108   add_view(_menu, view.get_top_level(), false);
00109 
00110   bool needs_separator = true;
00111 
00112   // And then the menu item(s) for each of the level values.
00113   const PStatClientData *client_data = _monitor->get_client_data();
00114   int num_toplevel_collectors = client_data->get_num_toplevel_collectors();
00115   for (int tc = 0; tc < num_toplevel_collectors; tc++) {
00116     int collector = client_data->get_toplevel_collector(tc);
00117     if (client_data->has_collector(collector) && 
00118         client_data->get_collector_has_level(collector, _thread_index)) {
00119 
00120       // We put a separator between the above frame collector and the
00121       // first level collector.
00122       if (needs_separator) {
00123   GtkWidget *sep = gtk_separator_menu_item_new();
00124   gtk_widget_show(sep);
00125   gtk_menu_shell_append(GTK_MENU_SHELL(_menu), sep);
00126 
00127         needs_separator = false;
00128       }
00129 
00130       PStatView &level_view = _monitor->get_level_view(collector, _thread_index);
00131       add_view(_menu, level_view.get_top_level(), true);
00132     }
00133   }
00134 
00135   // Also a menu item for a piano roll (following a separator).
00136   GtkWidget *sep = gtk_separator_menu_item_new();
00137   gtk_widget_show(sep);
00138   gtk_menu_shell_append(GTK_MENU_SHELL(_menu), sep);
00139   
00140   GtkStatsMonitor::MenuDef smd(_thread_index, -1, false);
00141   const GtkStatsMonitor::MenuDef *menu_def = _monitor->add_menu(smd);
00142 
00143   GtkWidget *menu_item = gtk_menu_item_new_with_label("Piano Roll");
00144   gtk_widget_show(menu_item);
00145   gtk_menu_shell_append(GTK_MENU_SHELL(_menu), menu_item);
00146 
00147   g_signal_connect_swapped(G_OBJECT(menu_item), "activate", 
00148          G_CALLBACK(handle_menu), (void *)(const void *)menu_def);
00149 }
00150 
00151 ////////////////////////////////////////////////////////////////////
00152 //     Function: GtkStatsChartMenu::add_view
00153 //       Access: Private
00154 //  Description: Adds a new entry or entries to the menu for the
00155 //               indicated view and its children.
00156 ////////////////////////////////////////////////////////////////////
00157 void GtkStatsChartMenu::
00158 add_view(GtkWidget *parent_menu, const PStatViewLevel *view_level, 
00159    bool show_level) {
00160   int collector = view_level->get_collector();
00161 
00162   const PStatClientData *client_data = _monitor->get_client_data();
00163   string collector_name = client_data->get_collector_name(collector);
00164 
00165   GtkStatsMonitor::MenuDef smd(_thread_index, collector, show_level);
00166   const GtkStatsMonitor::MenuDef *menu_def = _monitor->add_menu(smd);
00167 
00168   GtkWidget *menu_item = gtk_menu_item_new_with_label(collector_name.c_str());
00169   gtk_widget_show(menu_item);
00170   gtk_menu_shell_append(GTK_MENU_SHELL(parent_menu), menu_item);
00171 
00172   g_signal_connect_swapped(G_OBJECT(menu_item), "activate", 
00173          G_CALLBACK(handle_menu), (void *)(const void *)menu_def);
00174 
00175   int num_children = view_level->get_num_children();
00176   if (num_children > 1) {
00177     // If the collector has more than one child, add a menu entry to go
00178     // directly to each of its children.
00179     string submenu_name = collector_name + " components";
00180 
00181     GtkWidget *submenu_item = gtk_menu_item_new_with_label(submenu_name.c_str());
00182     gtk_widget_show(submenu_item);
00183     gtk_menu_shell_append(GTK_MENU_SHELL(parent_menu), submenu_item);
00184 
00185     GtkWidget *submenu = gtk_menu_new();
00186     gtk_widget_show(submenu);
00187     gtk_menu_item_set_submenu(GTK_MENU_ITEM(submenu_item), submenu);
00188 
00189     // Reverse the order since the menus are listed from the top down;
00190     // we want to be visually consistent with the graphs, which list
00191     // these labels from the bottom up.
00192     for (int c = num_children - 1; c >= 0; c--) {
00193       add_view(submenu, view_level->get_child(c), show_level);
00194     }
00195   }
00196 }
00197 
00198 ////////////////////////////////////////////////////////////////////
00199 //     Function: GtkStatsChartMenu::handle_menu
00200 //       Access: Private, Static
00201 //  Description: Callback when a menu item is selected.
00202 ////////////////////////////////////////////////////////////////////
00203 void GtkStatsChartMenu::
00204 handle_menu(gpointer data) {
00205   const GtkStatsMonitor::MenuDef *menu_def = (GtkStatsMonitor::MenuDef *)data;
00206   GtkStatsMonitor *monitor = menu_def->_monitor;
00207 
00208   if (monitor == NULL) {
00209     return;
00210   }
00211 
00212   if (menu_def->_collector_index < 0) {
00213     monitor->open_piano_roll(menu_def->_thread_index);
00214   } else {
00215     monitor->open_strip_chart(menu_def->_thread_index, 
00216             menu_def->_collector_index,
00217             menu_def->_show_level);
00218   }
00219 }
00220 
00221 ////////////////////////////////////////////////////////////////////
00222 //     Function: GtkStatsChartMenu::remove_menu_child
00223 //       Access: Private, Static
00224 //  Description: Removes a previous menu child from the menu.
00225 ////////////////////////////////////////////////////////////////////
00226 void GtkStatsChartMenu::
00227 remove_menu_child(GtkWidget *widget, gpointer data) {
00228   GtkWidget *menu = (GtkWidget *)data;
00229   gtk_container_remove(GTK_CONTAINER(menu), widget);
00230 }
 All Classes Functions Variables Enumerations