diff --git a/pandatool/src/gtk-stats/gtkStatsChartMenu.cxx b/pandatool/src/gtk-stats/gtkStatsChartMenu.cxx index d1e4e37095..7f0ad0a4bd 100644 --- a/pandatool/src/gtk-stats/gtkStatsChartMenu.cxx +++ b/pandatool/src/gtk-stats/gtkStatsChartMenu.cxx @@ -226,7 +226,7 @@ add_view(GtkWidget *parent_menu, const PStatViewLevel *view_level, } else if (menu_item != nullptr && menu == nullptr) { // Unhook the signal handler, we are creating a submenu. - GtkStatsMonitor::MenuDef smd(_thread_index, collector, GtkStatsMonitor::CT_strip_chart, show_level); + GtkStatsMonitor::MenuDef smd(GtkStatsMonitor::CT_strip_chart, _thread_index, collector, -1, show_level); const GtkStatsMonitor::MenuDef *menu_def = _monitor->add_menu(smd); g_signal_handlers_disconnect_by_data(G_OBJECT(menu_item), (void *)menu_def); @@ -277,7 +277,7 @@ add_view(GtkWidget *parent_menu, const PStatViewLevel *view_level, GtkWidget *GtkStatsChartMenu:: make_menu_item(const char *label, int collector_index, ChartType chart_type, bool show_level) { - GtkStatsMonitor::MenuDef smd(_thread_index, collector_index, chart_type, show_level); + GtkStatsMonitor::MenuDef smd(chart_type, _thread_index, collector_index, -1, show_level); const GtkStatsMonitor::MenuDef *menu_def = _monitor->add_menu(smd); GtkWidget *menu_item = gtk_menu_item_new_with_label(label); diff --git a/pandatool/src/gtk-stats/gtkStatsFlameGraph.cxx b/pandatool/src/gtk-stats/gtkStatsFlameGraph.cxx index dcd1491485..30bbd44751 100644 --- a/pandatool/src/gtk-stats/gtkStatsFlameGraph.cxx +++ b/pandatool/src/gtk-stats/gtkStatsFlameGraph.cxx @@ -24,13 +24,16 @@ static const int default_flame_graph_height = 150; */ GtkStatsFlameGraph:: GtkStatsFlameGraph(GtkStatsMonitor *monitor, int thread_index, - int collector_index) : - PStatFlameGraph(monitor, thread_index, collector_index, 0, 0), + int collector_index, int frame_number) : + PStatFlameGraph(monitor, thread_index, collector_index, frame_number, 0, 0), GtkStatsGraph(monitor, false) { // Let's show the units on the guide bar labels. There's room. set_guide_bar_units(get_guide_bar_units() | GBU_show_units); + std::string window_title = get_title_text(); + gtk_window_set_title(GTK_WINDOW(_window), window_title.c_str()); + // Put some stuff on top of the graph. _top_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start(GTK_BOX(_graph_vbox), _top_hbox, @@ -51,6 +54,13 @@ GtkStatsFlameGraph(GtkStatsMonitor *monitor, int thread_index, gtk_box_pack_start(GTK_BOX(_top_hbox), _scale_area, TRUE, TRUE, 0); gtk_box_pack_end(GTK_BOX(_top_hbox), _total_label, FALSE, FALSE, 0); + // Listen for mouse scroll and keyboard events. + gtk_widget_add_events(_window, GDK_SCROLL_MASK | GDK_KEY_PRESS_MASK); + g_signal_connect(G_OBJECT(_window), "scroll_event", + G_CALLBACK(scroll_callback), this); + g_signal_connect(G_OBJECT(_window), "key_press_event", + G_CALLBACK(key_press_callback), this); + gtk_widget_set_size_request(_graph_window, default_flame_graph_width * monitor->get_resolution() / 96, default_flame_graph_height * monitor->get_resolution() / 96); @@ -284,6 +294,15 @@ draw_bar(int depth, int from_x, int to_x, int collector_index, int parent_index) pango_layout_set_text(layout, def._name.c_str(), def._name.size()); } } + else if (collector_index == 0 && get_frame_number() >= 0) { + char text[32]; + sprintf(text, "Frame %d", get_frame_number()); + pango_layout_set_text(layout, text, -1); + if (pango_layout_is_ellipsized(layout)) { + // Nope, it's too long, go back. + pango_layout_set_text(layout, def._name.c_str(), def._name.size()); + } + } } int width, height; @@ -429,8 +448,7 @@ handle_button_press(int graph_x, int graph_y, bool double_click, int button) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - get_thread_index(), collector_index, - GtkStatsMonitor::CT_strip_chart, false, + GtkStatsMonitor::CT_strip_chart, get_thread_index(), collector_index, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Open Strip Chart"); @@ -442,8 +460,7 @@ handle_button_press(int graph_x, int graph_y, bool double_click, int button) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - get_thread_index(), collector_index, - GtkStatsMonitor::CT_flame_graph, + GtkStatsMonitor::CT_flame_graph, get_thread_index(), collector_index, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Open Flame Graph"); @@ -460,8 +477,7 @@ handle_button_press(int graph_x, int graph_y, bool double_click, int button) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - -1, collector_index, - GtkStatsMonitor::CT_choose_color, + GtkStatsMonitor::CT_choose_color, -1, collector_index, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Change Color..."); @@ -473,8 +489,7 @@ handle_button_press(int graph_x, int graph_y, bool double_click, int button) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - -1, collector_index, - GtkStatsMonitor::CT_reset_color, + GtkStatsMonitor::CT_reset_color, -1, collector_index, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Reset Color"); @@ -721,3 +736,63 @@ draw_callback(GtkWidget *widget, cairo_t *cr, gpointer data) { return TRUE; } + +/** + * + */ +gboolean GtkStatsFlameGraph:: +scroll_callback(GtkWidget *widget, GdkEventScroll *event, gpointer data) { + GtkStatsFlameGraph *self = (GtkStatsFlameGraph *)data; + bool changed = false; + switch (event->direction) { + case GDK_SCROLL_LEFT: + changed = self->prev_frame(); + break; + + case GDK_SCROLL_RIGHT: + changed = self->next_frame(); + break; + } + + if (changed) { + std::string window_title = self->get_title_text(); + gtk_window_set_title(GTK_WINDOW(self->_window), window_title.c_str()); + return TRUE; + } else { + return FALSE; + } +} + +/** + * + */ +gboolean GtkStatsFlameGraph:: +key_press_callback(GtkWidget *widget, GdkEventKey *event, gpointer data) { + GtkStatsFlameGraph *self = (GtkStatsFlameGraph *)data; + bool changed = false; + switch (event->keyval) { + case GDK_KEY_Left: + changed = self->prev_frame(); + break; + + case GDK_KEY_Right: + changed = self->next_frame(); + break; + + case GDK_KEY_Home: + changed = self->first_frame(); + break; + + case GDK_KEY_End: + changed = self->last_frame(); + break; + } + + if (changed) { + std::string window_title = self->get_title_text(); + gtk_window_set_title(GTK_WINDOW(self->_window), window_title.c_str()); + return TRUE; + } else { + return FALSE; + } +} diff --git a/pandatool/src/gtk-stats/gtkStatsFlameGraph.h b/pandatool/src/gtk-stats/gtkStatsFlameGraph.h index eb2eb5e5e4..1381ca801f 100644 --- a/pandatool/src/gtk-stats/gtkStatsFlameGraph.h +++ b/pandatool/src/gtk-stats/gtkStatsFlameGraph.h @@ -28,7 +28,7 @@ class GtkStatsLabel; class GtkStatsFlameGraph final : public PStatFlameGraph, public GtkStatsGraph { public: GtkStatsFlameGraph(GtkStatsMonitor *monitor, int thread_index, - int collector_index=-1); + int collector_index=-1, int frame_number=-1); virtual ~GtkStatsFlameGraph(); virtual void new_collector(int collector_index); @@ -76,6 +76,8 @@ private: static void toggled_callback(GtkToggleButton *button, gpointer data); static gboolean draw_callback(GtkWidget *widget, cairo_t *cr, gpointer data); + static gboolean scroll_callback(GtkWidget *widget, GdkEventScroll *event, gpointer data); + static gboolean key_press_callback(GtkWidget *widget, GdkEventKey *event, gpointer data); private: std::string _net_value_text; diff --git a/pandatool/src/gtk-stats/gtkStatsMonitor.I b/pandatool/src/gtk-stats/gtkStatsMonitor.I index b3e8e55b13..867c4349fb 100644 --- a/pandatool/src/gtk-stats/gtkStatsMonitor.I +++ b/pandatool/src/gtk-stats/gtkStatsMonitor.I @@ -15,10 +15,12 @@ * */ INLINE GtkStatsMonitor::MenuDef:: -MenuDef(int thread_index, int collector_index, ChartType chart_type, bool show_level) : +MenuDef(ChartType chart_type, int thread_index, int collector_index, + int frame_number, bool show_level) : + _chart_type(chart_type), _thread_index(thread_index), _collector_index(collector_index), - _chart_type(chart_type), + _frame_number(frame_number), _show_level(show_level), _monitor(nullptr) { @@ -29,14 +31,17 @@ MenuDef(int thread_index, int collector_index, ChartType chart_type, bool show_l */ INLINE bool GtkStatsMonitor::MenuDef:: operator < (const MenuDef &other) const { + if (_chart_type != other._chart_type) { + return _chart_type < other._chart_type; + } if (_thread_index != other._thread_index) { return _thread_index < other._thread_index; } if (_collector_index != other._collector_index) { return _collector_index < other._collector_index; } - if (_chart_type != other._chart_type) { - return _chart_type < other._chart_type; + if (_frame_number != other._frame_number) { + return _frame_number < other._frame_number; } return (int)_show_level < (int)other._show_level; } diff --git a/pandatool/src/gtk-stats/gtkStatsMonitor.cxx b/pandatool/src/gtk-stats/gtkStatsMonitor.cxx index 0410504457..2be16d9434 100644 --- a/pandatool/src/gtk-stats/gtkStatsMonitor.cxx +++ b/pandatool/src/gtk-stats/gtkStatsMonitor.cxx @@ -316,8 +316,8 @@ open_timeline() { * Opens a new flame graph showing the indicated data. */ PStatGraph *GtkStatsMonitor:: -open_flame_graph(int thread_index, int collector_index) { - GtkStatsFlameGraph *graph = new GtkStatsFlameGraph(this, thread_index, collector_index); +open_flame_graph(int thread_index, int collector_index, int frame_number) { + GtkStatsFlameGraph *graph = new GtkStatsFlameGraph(this, thread_index, collector_index, frame_number); add_graph(graph); return graph; } @@ -734,7 +734,7 @@ status_bar_button_event(GtkWidget *widget, GdkEventButton *event, gpointer data) const PStatViewLevel *child_level = view_level->get_child(c); int child_collector = child_level->get_collector(); - const MenuDef *menu_def = monitor->add_menu({0, child_collector, CT_strip_chart, true}); + const MenuDef *menu_def = monitor->add_menu({CT_strip_chart, 0, child_collector, -1, true}); double value = child_level->get_net_value(); @@ -787,7 +787,8 @@ menu_activate(GtkWidget *widget, gpointer data) { case CT_flame_graph: monitor->open_flame_graph(menu_def._thread_index, - menu_def._collector_index); + menu_def._collector_index, + menu_def._frame_number); break; case CT_piano_roll: @@ -853,7 +854,7 @@ handle_status_bar_popup(int item) { const PStatViewLevel *child_level = view_level->get_child(c); int child_collector = child_level->get_collector(); - const MenuDef *menu_def = add_menu({0, child_collector, CT_strip_chart, true}); + const MenuDef *menu_def = add_menu({CT_strip_chart, 0, child_collector, -1, true}); double value = child_level->get_net_value(); diff --git a/pandatool/src/gtk-stats/gtkStatsMonitor.h b/pandatool/src/gtk-stats/gtkStatsMonitor.h index 6a6c1e091f..3ac15abad5 100644 --- a/pandatool/src/gtk-stats/gtkStatsMonitor.h +++ b/pandatool/src/gtk-stats/gtkStatsMonitor.h @@ -46,13 +46,14 @@ public: class MenuDef { public: - INLINE MenuDef(int thread_index, int collector_index, - ChartType chart_type, bool show_level = false); + INLINE MenuDef(ChartType chart_type, int thread_index, int collector_index, + int frame_number = -1, bool show_level = false); INLINE bool operator < (const MenuDef &other) const; + ChartType _chart_type; int _thread_index; int _collector_index; - ChartType _chart_type; + int _frame_number; bool _show_level; GtkStatsMonitor *_monitor; }; @@ -84,7 +85,7 @@ public: PStatGraph *open_timeline(); PStatGraph *open_strip_chart(int thread_index, int collector_index, bool show_level); - PStatGraph *open_flame_graph(int thread_index, int collector_index = -1); + PStatGraph *open_flame_graph(int thread_index, int collector_index = -1, int frame_number = -1); PStatGraph *open_piano_roll(int thread_index); void choose_collector_color(int collector_index); diff --git a/pandatool/src/gtk-stats/gtkStatsPianoRoll.cxx b/pandatool/src/gtk-stats/gtkStatsPianoRoll.cxx index fbab6cb1ef..da5e6b3694 100644 --- a/pandatool/src/gtk-stats/gtkStatsPianoRoll.cxx +++ b/pandatool/src/gtk-stats/gtkStatsPianoRoll.cxx @@ -149,7 +149,7 @@ on_popup_label(int collector_index) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - _thread_index, collector_index, GtkStatsMonitor::CT_strip_chart, false, + GtkStatsMonitor::CT_strip_chart, _thread_index, collector_index, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Open Strip Chart"); @@ -161,7 +161,7 @@ on_popup_label(int collector_index) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - _thread_index, collector_index, GtkStatsMonitor::CT_flame_graph, + GtkStatsMonitor::CT_flame_graph, _thread_index, collector_index, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Open Flame Graph"); @@ -178,7 +178,7 @@ on_popup_label(int collector_index) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - -1, collector_index, GtkStatsMonitor::CT_choose_color, + GtkStatsMonitor::CT_choose_color, -1, collector_index, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Change Color..."); @@ -190,7 +190,7 @@ on_popup_label(int collector_index) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - -1, collector_index, GtkStatsMonitor::CT_reset_color, + GtkStatsMonitor::CT_reset_color, -1, collector_index, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Reset Color"); diff --git a/pandatool/src/gtk-stats/gtkStatsStripChart.cxx b/pandatool/src/gtk-stats/gtkStatsStripChart.cxx index f956cdfa9a..0be191da40 100644 --- a/pandatool/src/gtk-stats/gtkStatsStripChart.cxx +++ b/pandatool/src/gtk-stats/gtkStatsStripChart.cxx @@ -243,8 +243,8 @@ on_popup_label(int collector_index) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - _thread_index, collector_index, - GtkStatsMonitor::CT_strip_chart, get_view().get_show_level(), + GtkStatsMonitor::CT_strip_chart, _thread_index, collector_index, -1, + get_view().get_show_level(), }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Open Strip Chart"); @@ -256,7 +256,7 @@ on_popup_label(int collector_index) { if (!get_view().get_show_level()) { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - _thread_index, collector_index, GtkStatsMonitor::CT_flame_graph, + GtkStatsMonitor::CT_flame_graph, _thread_index, collector_index, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Open Flame Graph"); @@ -273,7 +273,7 @@ on_popup_label(int collector_index) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - -1, collector_index, GtkStatsMonitor::CT_choose_color, + GtkStatsMonitor::CT_choose_color, -1, collector_index, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Change Color..."); @@ -285,7 +285,7 @@ on_popup_label(int collector_index) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - -1, collector_index, GtkStatsMonitor::CT_reset_color, + GtkStatsMonitor::CT_reset_color, -1, collector_index, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Reset Color"); diff --git a/pandatool/src/gtk-stats/gtkStatsTimeline.cxx b/pandatool/src/gtk-stats/gtkStatsTimeline.cxx index a58100f637..5010b2dabc 100644 --- a/pandatool/src/gtk-stats/gtkStatsTimeline.cxx +++ b/pandatool/src/gtk-stats/gtkStatsTimeline.cxx @@ -409,8 +409,8 @@ handle_button_press(int graph_x, int graph_y, bool double_click, int button) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ + GtkStatsMonitor::CT_strip_chart, bar._thread_index, bar._collector_index, - GtkStatsMonitor::CT_strip_chart, false, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Open Strip Chart"); @@ -422,8 +422,8 @@ handle_button_press(int graph_x, int graph_y, bool double_click, int button) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - bar._thread_index, bar._collector_index, GtkStatsMonitor::CT_flame_graph, + bar._thread_index, bar._collector_index, bar._frame_number, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Open Flame Graph"); @@ -435,7 +435,7 @@ handle_button_press(int graph_x, int graph_y, bool double_click, int button) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - bar._thread_index, -1, GtkStatsMonitor::CT_piano_roll, + GtkStatsMonitor::CT_piano_roll, bar._thread_index, -1, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Open Piano Roll"); @@ -452,8 +452,7 @@ handle_button_press(int graph_x, int graph_y, bool double_click, int button) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - -1, bar._collector_index, - GtkStatsMonitor::CT_choose_color, + GtkStatsMonitor::CT_choose_color, -1, bar._collector_index, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Change Color..."); @@ -465,8 +464,7 @@ handle_button_press(int graph_x, int graph_y, bool double_click, int button) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - -1, bar._collector_index, - GtkStatsMonitor::CT_reset_color, + GtkStatsMonitor::CT_reset_color, -1, bar._collector_index, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Reset Color"); diff --git a/pandatool/src/mac-stats/macStatsFlameGraph.h b/pandatool/src/mac-stats/macStatsFlameGraph.h index 25df1f96c8..62c7f27472 100644 --- a/pandatool/src/mac-stats/macStatsFlameGraph.h +++ b/pandatool/src/mac-stats/macStatsFlameGraph.h @@ -25,7 +25,7 @@ class MacStatsFlameGraph final : public PStatFlameGraph, public MacStatsGraph { public: MacStatsFlameGraph(MacStatsMonitor *monitor, int thread_index, - int collector_index=-1); + int collector_index=-1, int frame_number=-1); virtual ~MacStatsFlameGraph(); virtual void new_collector(int collector_index); @@ -60,11 +60,14 @@ protected: virtual std::string get_graph_tooltip(int mouse_x, int mouse_y) const; virtual DragMode consider_drag_start(int graph_x, int graph_y); + virtual bool handle_key(int graph_x, int graph_y, bool pressed, + UniChar c, unsigned short key_code); virtual void handle_button_press(int graph_x, int graph_y, - bool double_click, int button); + bool double_click, int button); virtual void handle_button_release(int graph_x, int graph_y); virtual void handle_motion(int graph_x, int graph_y); virtual void handle_leave(); + virtual void handle_wheel(int graph_x, int graph_y, double dx, double dy); virtual void handle_draw_graph(CGContextRef ctx, NSRect rect); virtual void handle_back(); diff --git a/pandatool/src/mac-stats/macStatsFlameGraph.mm b/pandatool/src/mac-stats/macStatsFlameGraph.mm index 60314147f8..b241b401f8 100644 --- a/pandatool/src/mac-stats/macStatsFlameGraph.mm +++ b/pandatool/src/mac-stats/macStatsFlameGraph.mm @@ -29,8 +29,8 @@ static const int default_flame_graph_height = 250; */ MacStatsFlameGraph:: MacStatsFlameGraph(MacStatsMonitor *monitor, int thread_index, - int collector_index) : - PStatFlameGraph(monitor, thread_index, collector_index, 0, 0), + int collector_index, int frame_number) : + PStatFlameGraph(monitor, thread_index, collector_index, frame_number, 0, 0), MacStatsGraph(monitor, [MacStatsFlameGraphViewController alloc]) { // Used for popup menus. @@ -538,6 +538,43 @@ consider_drag_start(int graph_x, int graph_y) { return DM_none; } +/** + * + */ +bool MacStatsFlameGraph:: +handle_key(int graph_x, int graph_y, bool pressed, UniChar c, unsigned short key_code) { + bool changed = false; + + if (pressed) { + switch (c) { + case NSLeftArrowFunctionKey: + changed = prev_frame(); + break; + + case NSRightArrowFunctionKey: + changed = next_frame(); + break; + + case NSHomeFunctionKey: + changed = first_frame(); + break; + + case NSEndFunctionKey: + changed = last_frame(); + break; + } + } + + if (changed) { + std::string window_title = get_title_text(); + if (!is_title_unknown()) { + _window.title = [NSString stringWithUTF8String:window_title.c_str()]; + } + } + + return changed; +} + /** * Called when the mouse button is depressed within the graph window. */ @@ -652,6 +689,21 @@ handle_leave() { return; } +/** + * + */ +void MacStatsFlameGraph:: +handle_wheel(int graph_x, int graph_y, double dx, double dy) { + if (dx != 0.0) { + if ((dx > 0.0) ? prev_frame() : next_frame()) { + std::string window_title = get_title_text(); + if (!is_title_unknown()) { + _window.title = [NSString stringWithUTF8String:window_title.c_str()]; + } + } + } +} + /** * Fills in the graph window. */ diff --git a/pandatool/src/mac-stats/macStatsGraphView.mm b/pandatool/src/mac-stats/macStatsGraphView.mm index 013b424139..82b2d5d8e8 100644 --- a/pandatool/src/mac-stats/macStatsGraphView.mm +++ b/pandatool/src/mac-stats/macStatsGraphView.mm @@ -45,15 +45,13 @@ } - (void)keyDown:(NSEvent *)event { - if (!event.isARepeat) { - NSPoint pos = [self convertPoint:event.locationInWindow fromView:nil]; - UniChar c = 0; - NSString *str = [event charactersIgnoringModifiers]; - if (str != nil && str.length == 1) { - c = [str characterAtIndex:0]; - } - _graph->handle_key(pos.x, pos.y, true, c, event.keyCode); + NSPoint pos = [self convertPoint:event.locationInWindow fromView:nil]; + UniChar c = 0; + NSString *str = [event charactersIgnoringModifiers]; + if (str != nil && str.length == 1) { + c = [str characterAtIndex:0]; } + _graph->handle_key(pos.x, pos.y, true, c, event.keyCode); } - (void)keyUp:(NSEvent *)event { diff --git a/pandatool/src/mac-stats/macStatsMonitor.h b/pandatool/src/mac-stats/macStatsMonitor.h index 8e12677963..8c5d0c3164 100644 --- a/pandatool/src/mac-stats/macStatsMonitor.h +++ b/pandatool/src/mac-stats/macStatsMonitor.h @@ -57,7 +57,7 @@ public: PStatGraph *open_timeline(); PStatGraph *open_strip_chart(int thread_index, int collector_index, bool show_level); - PStatGraph *open_flame_graph(int thread_index, int collector_index = -1); + PStatGraph *open_flame_graph(int thread_index, int collector_index = -1, int frame_number = -1); PStatGraph *open_piano_roll(int thread_index); CGColorRef get_collector_color(int collector_index, bool highlight = false); diff --git a/pandatool/src/mac-stats/macStatsMonitor.mm b/pandatool/src/mac-stats/macStatsMonitor.mm index 7d001e39a5..57245e0208 100644 --- a/pandatool/src/mac-stats/macStatsMonitor.mm +++ b/pandatool/src/mac-stats/macStatsMonitor.mm @@ -312,9 +312,9 @@ open_timeline() { * Opens a new flame graph showing the indicated data. */ PStatGraph *MacStatsMonitor:: -open_flame_graph(int thread_index, int collector_index) { +open_flame_graph(int thread_index, int collector_index, int frame_number) { MacStatsFlameGraph *graph = - new MacStatsFlameGraph(this, thread_index, collector_index); + new MacStatsFlameGraph(this, thread_index, collector_index, frame_number); add_graph(graph); return graph; } diff --git a/pandatool/src/mac-stats/macStatsTimeline.mm b/pandatool/src/mac-stats/macStatsTimeline.mm index 464edde12d..85f5c89e30 100644 --- a/pandatool/src/mac-stats/macStatsTimeline.mm +++ b/pandatool/src/mac-stats/macStatsTimeline.mm @@ -819,7 +819,7 @@ handle_open_strip_chart() { void MacStatsTimeline:: handle_open_flame_graph() { const ColorBar &bar = _popup_bar; - MacStatsGraph::_monitor->open_flame_graph(bar._thread_index, bar._collector_index); + MacStatsGraph::_monitor->open_flame_graph(bar._thread_index, bar._collector_index, bar._frame_number); } /** diff --git a/pandatool/src/pstatserver/pStatFlameGraph.I b/pandatool/src/pstatserver/pStatFlameGraph.I index 2ab06a159c..b2363d5a4f 100644 --- a/pandatool/src/pstatserver/pStatFlameGraph.I +++ b/pandatool/src/pstatserver/pStatFlameGraph.I @@ -27,6 +27,15 @@ get_collector_index() const { return _collector_index; } +/** + * Returns the particular frame number whose data this flame graph reflects. + * Returns -1 if we're looking at a moving average instead. + */ +INLINE int PStatFlameGraph:: +get_frame_number() const { + return _frame_number; +} + /** * Returns the amount of total time the width of the horizontal axis * represents. diff --git a/pandatool/src/pstatserver/pStatFlameGraph.cxx b/pandatool/src/pstatserver/pStatFlameGraph.cxx index b549be26bf..48039d992b 100644 --- a/pandatool/src/pstatserver/pStatFlameGraph.cxx +++ b/pandatool/src/pstatserver/pStatFlameGraph.cxx @@ -25,12 +25,13 @@ * */ PStatFlameGraph:: -PStatFlameGraph(PStatMonitor *monitor, - int thread_index, int collector_index, int xsize, int ysize) : +PStatFlameGraph(PStatMonitor *monitor, int thread_index, int collector_index, + int frame_number, int xsize, int ysize) : PStatGraph(monitor, xsize, ysize), _thread_index(thread_index), _collector_index(collector_index), - _orig_collector_index(collector_index) + _orig_collector_index(collector_index), + _frame_number(frame_number) { _average_mode = true; _average_cursor = 0; @@ -73,11 +74,20 @@ update() { const PStatThreadData *thread_data = client_data->get_thread_data(_thread_index); if (!thread_data->is_empty()) { - int frame_number = thread_data->get_latest_frame_number(); - if (frame_number != _current_frame) { - _current_frame = frame_number; + if (_frame_number >= 0) { + if (thread_data->has_frame(_frame_number)) { + if (_current_frame != _frame_number) { + _current_frame = _frame_number; + update_data(); + } + } + } else { + int frame_number = thread_data->get_latest_frame_number(); + if (frame_number != _current_frame) { + _current_frame = frame_number; - update_data(); + update_data(); + } } } } @@ -117,6 +127,142 @@ set_collector_index(int collector_index) { } } +/** + * Changes the frame number shown by this flame graph. This may force a redraw. + */ +void PStatFlameGraph:: +set_frame_number(int frame_number) { + if (_frame_number != frame_number) { + _frame_number = frame_number; + _current_frame = frame_number; + _title_unknown = true; + _stack.clear(); + update_data(); + + if (_average_mode) { + _stack.update_averages(_average_cursor); + _time_width = _stack.get_net_value(true); + if (_time_width == 0.0) { + _time_width = 1.0 / pstats_target_frame_rate; + } + normal_guide_bars(); + } + } +} + +/** + * Sets the frame number to the oldest available frame. + */ +bool PStatFlameGraph:: +first_frame() { + const PStatClientData *client_data = _monitor->get_client_data(); + if (client_data == nullptr) { + return false; + } + + const PStatThreadData *thread_data = client_data->get_thread_data(_thread_index); + if (thread_data == nullptr || thread_data->is_empty()) { + return false; + } + + int oldest = thread_data->get_oldest_frame_number(); + if (_frame_number != oldest && thread_data->has_frame(oldest)) { + set_frame_number(oldest); + return true; + } + return false; +} + +/** + * Advances to the next available frame. Returns true if the frame number was + * changed after a call to this method. + */ +bool PStatFlameGraph:: +next_frame() { + const PStatClientData *client_data = _monitor->get_client_data(); + if (client_data == nullptr) { + return false; + } + + const PStatThreadData *thread_data = client_data->get_thread_data(_thread_index); + if (thread_data == nullptr || thread_data->is_empty()) { + return false; + } + + int latest = thread_data->get_latest_frame_number(); + if (_frame_number < 0 || _frame_number > latest) { + set_frame_number(latest); + return true; + } + + for (int i = _frame_number + 1; i <= latest; ++i) { + if (thread_data->has_frame(i)) { + set_frame_number(i); + return true; + } + } + + return false; +} + +/** + * Reverts to the previous frame. Returns true if the frame number was changed + * after a call to this method. + */ +bool PStatFlameGraph:: +prev_frame() { + const PStatClientData *client_data = _monitor->get_client_data(); + if (client_data == nullptr) { + return false; + } + + const PStatThreadData *thread_data = client_data->get_thread_data(_thread_index); + if (thread_data == nullptr || thread_data->is_empty()) { + return false; + } + + int oldest = thread_data->get_oldest_frame_number(); + + int i; + if (_frame_number < 0) { + i = thread_data->get_latest_frame_number(); + } else { + i = _frame_number - 1; + } + while (i >= oldest) { + if (thread_data->has_frame(i)) { + set_frame_number(i); + return true; + } + --i; + } + + return false; +} + +/** + * Sets the frame number to the latest available frame. + */ +bool PStatFlameGraph:: +last_frame() { + const PStatClientData *client_data = _monitor->get_client_data(); + if (client_data == nullptr) { + return false; + } + + const PStatThreadData *thread_data = client_data->get_thread_data(_thread_index); + if (thread_data == nullptr || thread_data->is_empty()) { + return false; + } + + int latest = thread_data->get_latest_frame_number(); + if (_frame_number != latest && thread_data->has_frame(latest)) { + set_frame_number(latest); + return true; + } + return false; +} + /** * Returns the text suitable for the title label on the top line. */ @@ -150,6 +296,10 @@ get_title_text() { _title_unknown = true; } + if (_frame_number >= 0) { + text += " (frame " + format_string(_frame_number) + ")"; + } + return text; } diff --git a/pandatool/src/pstatserver/pStatFlameGraph.h b/pandatool/src/pstatserver/pStatFlameGraph.h index 721651e43d..25698a935b 100644 --- a/pandatool/src/pstatserver/pStatFlameGraph.h +++ b/pandatool/src/pstatserver/pStatFlameGraph.h @@ -36,7 +36,7 @@ class PStatFrameData; class PStatFlameGraph : public PStatGraph { public: PStatFlameGraph(PStatMonitor *monitor, - int thread_index, int collector_index, + int thread_index, int collector_index, int frame_number, int xsize, int ysize); virtual ~PStatFlameGraph(); @@ -46,6 +46,13 @@ public: INLINE int get_collector_index() const; void set_collector_index(int collector_index); + INLINE int get_frame_number() const; + void set_frame_number(int collector_index); + bool first_frame(); + bool next_frame(); + bool prev_frame(); + bool last_frame(); + INLINE double get_horizontal_scale() const; INLINE void set_average_mode(bool average_mode); @@ -123,6 +130,7 @@ private: int _thread_index; int _collector_index; int _orig_collector_index; + int _frame_number; bool _average_mode; size_t _average_cursor; diff --git a/pandatool/src/pstatserver/pStatMonitor.cxx b/pandatool/src/pstatserver/pStatMonitor.cxx index 86390d5ab7..cbc49a7140 100644 --- a/pandatool/src/pstatserver/pStatMonitor.cxx +++ b/pandatool/src/pstatserver/pStatMonitor.cxx @@ -654,7 +654,7 @@ open_strip_chart(int thread_index, int collector_index, bool show_level) { * Opens a new flame graph showing the indicated data. */ PStatGraph *PStatMonitor:: -open_flame_graph(int thread_index, int collector_index) { +open_flame_graph(int thread_index, int collector_index, int frame_number) { return nullptr; } diff --git a/pandatool/src/pstatserver/pStatMonitor.h b/pandatool/src/pstatserver/pStatMonitor.h index 5e71be4b53..d98ce2b9b0 100644 --- a/pandatool/src/pstatserver/pStatMonitor.h +++ b/pandatool/src/pstatserver/pStatMonitor.h @@ -104,7 +104,7 @@ public: virtual PStatGraph *open_timeline(); virtual PStatGraph *open_strip_chart(int thread_index, int collector_index, bool show_level); - virtual PStatGraph *open_flame_graph(int thread_index, int collector_index = -1); + virtual PStatGraph *open_flame_graph(int thread_index, int collector_index = -1, int frame_number = -1); virtual PStatGraph *open_piano_roll(int thread_index); void write_datagram(Datagram &dg) const; diff --git a/pandatool/src/win-stats/winStatsFlameGraph.cxx b/pandatool/src/win-stats/winStatsFlameGraph.cxx index 3b1f991dba..2ad8415369 100644 --- a/pandatool/src/win-stats/winStatsFlameGraph.cxx +++ b/pandatool/src/win-stats/winStatsFlameGraph.cxx @@ -29,9 +29,9 @@ const char * const WinStatsFlameGraph::_window_class_name = "flame"; */ WinStatsFlameGraph:: WinStatsFlameGraph(WinStatsMonitor *monitor, int thread_index, - int collector_index) : + int collector_index, int frame_number) : PStatFlameGraph(monitor, - thread_index, collector_index, + thread_index, collector_index, frame_number, monitor->get_pixel_scale() * default_flame_graph_width / 4, monitor->get_pixel_scale() * default_flame_graph_height / 4), WinStatsGraph(monitor) @@ -349,6 +349,7 @@ LONG WinStatsFlameGraph:: window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { switch (msg) { case WM_LBUTTONDOWN: + SetFocus(_window); if (_potential_drag_mode == DM_new_guide_bar) { set_drag_mode(DM_new_guide_bar); SetCapture(_graph_window); @@ -393,6 +394,31 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { } break; + case WM_KEYDOWN: + { + bool changed = false; + switch (wparam) { + case VK_LEFT: + changed = prev_frame(); + break; + case VK_RIGHT: + changed = next_frame(); + break; + case VK_HOME: + changed = first_frame(); + break; + case VK_END: + changed = last_frame(); + break; + } + if (changed) { + std::string window_title = get_title_text(); + SetWindowText(_window, window_title.c_str()); + return 0; + } + } + break; + default: break; } @@ -407,6 +433,7 @@ LONG WinStatsFlameGraph:: graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { switch (msg) { case WM_LBUTTONDOWN: + SetFocus(_window); if (_potential_drag_mode == DM_guide_bar && _drag_guide_bar >= 0) { set_drag_mode(DM_guide_bar); int16_t x = LOWORD(lparam); @@ -518,6 +545,19 @@ graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { } break; + case WM_MOUSEHWHEEL: + { + int delta = GET_WHEEL_DELTA_WPARAM(wparam); + if (delta != 0) { + if (delta > 0 ? next_frame() : prev_frame()) { + std::string window_title = get_title_text(); + SetWindowText(_window, window_title.c_str()); + } + } + return 0; + } + break; + default: break; } @@ -760,6 +800,8 @@ create_window() { // Ensure that the window is on top of the stack. SetWindowPos(_window, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); + + SetFocus(_window); } /** diff --git a/pandatool/src/win-stats/winStatsFlameGraph.h b/pandatool/src/win-stats/winStatsFlameGraph.h index 950f046b17..51fc42a266 100644 --- a/pandatool/src/win-stats/winStatsFlameGraph.h +++ b/pandatool/src/win-stats/winStatsFlameGraph.h @@ -28,7 +28,7 @@ class WinStatsLabel; class WinStatsFlameGraph : public PStatFlameGraph, public WinStatsGraph { public: WinStatsFlameGraph(WinStatsMonitor *monitor, int thread_index, - int collector_index=-1); + int collector_index=-1, int frame_number=-1); virtual ~WinStatsFlameGraph(); virtual void new_data(int thread_index, int frame_number); diff --git a/pandatool/src/win-stats/winStatsMonitor.cxx b/pandatool/src/win-stats/winStatsMonitor.cxx index 18623f5c66..410d638884 100644 --- a/pandatool/src/win-stats/winStatsMonitor.cxx +++ b/pandatool/src/win-stats/winStatsMonitor.cxx @@ -332,8 +332,8 @@ open_strip_chart(int thread_index, int collector_index, bool show_level) { * Opens a new flame graph showing the indicated data. */ PStatGraph *WinStatsMonitor:: -open_flame_graph(int thread_index, int collector_index) { - WinStatsFlameGraph *graph = new WinStatsFlameGraph(this, thread_index, collector_index); +open_flame_graph(int thread_index, int collector_index, int frame_number) { + WinStatsFlameGraph *graph = new WinStatsFlameGraph(this, thread_index, collector_index, frame_number); add_graph(graph); return graph; } diff --git a/pandatool/src/win-stats/winStatsMonitor.h b/pandatool/src/win-stats/winStatsMonitor.h index 34338dc1a0..1fed3f9a9f 100644 --- a/pandatool/src/win-stats/winStatsMonitor.h +++ b/pandatool/src/win-stats/winStatsMonitor.h @@ -84,7 +84,7 @@ public: PStatGraph *open_timeline(); PStatGraph *open_strip_chart(int thread_index, int collector_index, bool show_level); - PStatGraph *open_flame_graph(int thread_index, int collector_index = -1); + PStatGraph *open_flame_graph(int thread_index, int collector_index = -1, int frame_number = -1); PStatGraph *open_piano_roll(int thread_index); void choose_collector_color(int collector_index); diff --git a/pandatool/src/win-stats/winStatsTimeline.cxx b/pandatool/src/win-stats/winStatsTimeline.cxx index 6a53415253..a9c3f6688a 100644 --- a/pandatool/src/win-stats/winStatsTimeline.cxx +++ b/pandatool/src/win-stats/winStatsTimeline.cxx @@ -463,7 +463,7 @@ graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { return 0; case 103: - WinStatsGraph::_monitor->open_flame_graph(_popup_bar._thread_index, _popup_bar._collector_index); + WinStatsGraph::_monitor->open_flame_graph(_popup_bar._thread_index, _popup_bar._collector_index, _popup_bar._frame_number); return 0; case 104: