Panda3D
gtkStatsChartMenu.cxx
1 // Filename: gtkStatsChartMenu.cxx
2 // Created by: drose (16Jan06)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "gtkStatsChartMenu.h"
16 #include "gtkStatsMonitor.h"
17 
18 ////////////////////////////////////////////////////////////////////
19 // Function: GtkStatsChartMenu::Constructor
20 // Access: Public
21 // Description:
22 ////////////////////////////////////////////////////////////////////
23 GtkStatsChartMenu::
24 GtkStatsChartMenu(GtkStatsMonitor *monitor, int thread_index) :
25  _monitor(monitor),
26  _thread_index(thread_index)
27 {
28  _menu = gtk_menu_new();
29  gtk_widget_show(_menu);
30  do_update();
31 }
32 
33 ////////////////////////////////////////////////////////////////////
34 // Function: GtkStatsChartMenu::Destructor
35 // Access: Public
36 // Description:
37 ////////////////////////////////////////////////////////////////////
38 GtkStatsChartMenu::
39 ~GtkStatsChartMenu() {
40 }
41 
42 ////////////////////////////////////////////////////////////////////
43 // Function: GtkStatsChartMenu::get_menu_widget
44 // Access: Public
45 // Description: Returns the gtk widget for this particular
46 // menu.
47 ////////////////////////////////////////////////////////////////////
48 GtkWidget *GtkStatsChartMenu::
50  return _menu;
51 }
52 
53 ////////////////////////////////////////////////////////////////////
54 // Function: GtkStatsChartMenu::add_to_menu_bar
55 // Access: Public
56 // Description: Adds the menu to the end of the indicated menu bar.
57 ////////////////////////////////////////////////////////////////////
59 add_to_menu_bar(GtkWidget *menu_bar, int position) {
60  const PStatClientData *client_data = _monitor->get_client_data();
61  string thread_name;
62  if (_thread_index == 0) {
63  // A special case for the main thread.
64  thread_name = "Graphs";
65  } else {
66  thread_name = client_data->get_thread_name(_thread_index);
67  }
68 
69  GtkWidget *menu_item = gtk_menu_item_new_with_label(thread_name.c_str());
70  gtk_widget_show(menu_item);
71  gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), _menu);
72 
73  gtk_menu_shell_insert(GTK_MENU_SHELL(menu_bar), menu_item, position);
74 }
75 
76 ////////////////////////////////////////////////////////////////////
77 // Function: GtkStatsChartMenu::check_update
78 // Access: Public
79 // Description: Checks to see if the menu needs to be updated
80 // (e.g. because of new data from the client), and
81 // updates it if necessary.
82 ////////////////////////////////////////////////////////////////////
85  PStatView &view = _monitor->get_view(_thread_index);
86  if (view.get_level_index() != _last_level_index) {
87  do_update();
88  }
89 }
90 
91 ////////////////////////////////////////////////////////////////////
92 // Function: GtkStatsChartMenu::do_update
93 // Access: Public
94 // Description: Unconditionally updates the menu with the latest data
95 // from the client.
96 ////////////////////////////////////////////////////////////////////
99  PStatView &view = _monitor->get_view(_thread_index);
100  _last_level_index = view.get_level_index();
101 
102  // First, remove all of the old entries from the menu.
103  gtk_container_foreach(GTK_CONTAINER(_menu), remove_menu_child, _menu);
104 
105  // Now rebuild the menu with the new set of entries.
106 
107  // The menu item(s) for the thread's frame time goes first.
108  add_view(_menu, view.get_top_level(), false);
109 
110  bool needs_separator = true;
111 
112  // And then the menu item(s) for each of the level values.
113  const PStatClientData *client_data = _monitor->get_client_data();
114  int num_toplevel_collectors = client_data->get_num_toplevel_collectors();
115  for (int tc = 0; tc < num_toplevel_collectors; tc++) {
116  int collector = client_data->get_toplevel_collector(tc);
117  if (client_data->has_collector(collector) &&
118  client_data->get_collector_has_level(collector, _thread_index)) {
119 
120  // We put a separator between the above frame collector and the
121  // first level collector.
122  if (needs_separator) {
123  GtkWidget *sep = gtk_separator_menu_item_new();
124  gtk_widget_show(sep);
125  gtk_menu_shell_append(GTK_MENU_SHELL(_menu), sep);
126 
127  needs_separator = false;
128  }
129 
130  PStatView &level_view = _monitor->get_level_view(collector, _thread_index);
131  add_view(_menu, level_view.get_top_level(), true);
132  }
133  }
134 
135  // Also a menu item for a piano roll (following a separator).
136  GtkWidget *sep = gtk_separator_menu_item_new();
137  gtk_widget_show(sep);
138  gtk_menu_shell_append(GTK_MENU_SHELL(_menu), sep);
139 
140  GtkStatsMonitor::MenuDef smd(_thread_index, -1, false);
141  const GtkStatsMonitor::MenuDef *menu_def = _monitor->add_menu(smd);
142 
143  GtkWidget *menu_item = gtk_menu_item_new_with_label("Piano Roll");
144  gtk_widget_show(menu_item);
145  gtk_menu_shell_append(GTK_MENU_SHELL(_menu), menu_item);
146 
147  g_signal_connect_swapped(G_OBJECT(menu_item), "activate",
148  G_CALLBACK(handle_menu), (void *)(const void *)menu_def);
149 }
150 
151 ////////////////////////////////////////////////////////////////////
152 // Function: GtkStatsChartMenu::add_view
153 // Access: Private
154 // Description: Adds a new entry or entries to the menu for the
155 // indicated view and its children.
156 ////////////////////////////////////////////////////////////////////
157 void GtkStatsChartMenu::
158 add_view(GtkWidget *parent_menu, const PStatViewLevel *view_level,
159  bool show_level) {
160  int collector = view_level->get_collector();
161 
162  const PStatClientData *client_data = _monitor->get_client_data();
163  string collector_name = client_data->get_collector_name(collector);
164 
165  GtkStatsMonitor::MenuDef smd(_thread_index, collector, show_level);
166  const GtkStatsMonitor::MenuDef *menu_def = _monitor->add_menu(smd);
167 
168  GtkWidget *menu_item = gtk_menu_item_new_with_label(collector_name.c_str());
169  gtk_widget_show(menu_item);
170  gtk_menu_shell_append(GTK_MENU_SHELL(parent_menu), menu_item);
171 
172  g_signal_connect_swapped(G_OBJECT(menu_item), "activate",
173  G_CALLBACK(handle_menu), (void *)(const void *)menu_def);
174 
175  int num_children = view_level->get_num_children();
176  if (num_children > 1) {
177  // If the collector has more than one child, add a menu entry to go
178  // directly to each of its children.
179  string submenu_name = collector_name + " components";
180 
181  GtkWidget *submenu_item = gtk_menu_item_new_with_label(submenu_name.c_str());
182  gtk_widget_show(submenu_item);
183  gtk_menu_shell_append(GTK_MENU_SHELL(parent_menu), submenu_item);
184 
185  GtkWidget *submenu = gtk_menu_new();
186  gtk_widget_show(submenu);
187  gtk_menu_item_set_submenu(GTK_MENU_ITEM(submenu_item), submenu);
188 
189  // Reverse the order since the menus are listed from the top down;
190  // we want to be visually consistent with the graphs, which list
191  // these labels from the bottom up.
192  for (int c = num_children - 1; c >= 0; c--) {
193  add_view(submenu, view_level->get_child(c), show_level);
194  }
195  }
196 }
197 
198 ////////////////////////////////////////////////////////////////////
199 // Function: GtkStatsChartMenu::handle_menu
200 // Access: Private, Static
201 // Description: Callback when a menu item is selected.
202 ////////////////////////////////////////////////////////////////////
203 void GtkStatsChartMenu::
204 handle_menu(gpointer data) {
205  const GtkStatsMonitor::MenuDef *menu_def = (GtkStatsMonitor::MenuDef *)data;
206  GtkStatsMonitor *monitor = menu_def->_monitor;
207 
208  if (monitor == NULL) {
209  return;
210  }
211 
212  if (menu_def->_collector_index < 0) {
213  monitor->open_piano_roll(menu_def->_thread_index);
214  } else {
215  monitor->open_strip_chart(menu_def->_thread_index,
216  menu_def->_collector_index,
217  menu_def->_show_level);
218  }
219 }
220 
221 ////////////////////////////////////////////////////////////////////
222 // Function: GtkStatsChartMenu::remove_menu_child
223 // Access: Private, Static
224 // Description: Removes a previous menu child from the menu.
225 ////////////////////////////////////////////////////////////////////
226 void GtkStatsChartMenu::
227 remove_menu_child(GtkWidget *widget, gpointer data) {
228  GtkWidget *menu = (GtkWidget *)data;
229  gtk_container_remove(GTK_CONTAINER(menu), widget);
230 }
const PStatViewLevel * get_top_level()
Returns a pointer to the level that corresponds to the Collector we&#39;ve constrained to...
Definition: pStatView.cxx:270
void check_update()
Checks to see if the menu needs to be updated (e.g.
int get_toplevel_collector(int index) const
Returns the collector index of the nth toplevel collector.
void open_piano_roll(int thread_index)
Opens a new piano roll showing the indicated data.
PStatView & get_level_view(int collector_index, int thread_index)
Returns a view on the level value (as opposed to elapsed time) for the given collector over the given...
const PStatViewLevel * get_child(int n) const
Returns the nth child of this Level/Collector.
void do_update()
Unconditionally updates the menu with the latest data from the client.
The data associated with a particular client, but not with any one particular frame or thread: the li...
string get_collector_name(int index) const
Returns the name of the indicated collector.
This is a single level value, or band of color, within a View.
GtkWidget * get_menu_widget()
Returns the gtk widget for this particular menu.
bool has_collector(int index) const
Returns true if the indicated collector has been defined by the client already, false otherwise...
A View boils down the frame data to a linear list of times spent in a number of different Collectors...
Definition: pStatView.h:34
PStatView & get_view(int thread_index)
Returns a view on the given thread index.
void add_to_menu_bar(GtkWidget *menu_bar, int position)
Adds the menu to the end of the indicated menu bar.
const MenuDef * add_menu(const MenuDef &menu_def)
Adds a new MenuDef to the monitor, or returns an existing one if there is already one just like it...
This class represents a connection to a PStatsClient and manages the data exchange with the client...
void open_strip_chart(int thread_index, int collector_index, bool show_level)
Opens a new strip chart showing the indicated data.
int get_collector() const
Returns the Collector index associated with this level.
int get_level_index() const
Returns an index number that can be used to determine when the set of known levels has changed...
Definition: pStatView.I:89
const PStatClientData * get_client_data() const
Returns the client data associated with this monitor.
Definition: pStatMonitor.I:32
int get_num_children() const
Returns the number of children of this Level/Collector.
int get_num_toplevel_collectors() const
Returns the total number of collectors that are toplevel collectors.
string get_thread_name(int index) const
Returns the name of the indicated thread.
bool get_collector_has_level(int index, int thread_index) const
Returns whether the given collector has level data (and consequently, whether it should appear on the...