From 0f5505382ec4014e667425ec33ad2a8f0a09d9bf Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 17 Jan 2006 23:17:59 +0000 Subject: [PATCH] getting closer --- pandatool/src/gtk-stats/Sources.pp | 4 +- pandatool/src/gtk-stats/gtkStatsGraph.cxx | 216 +++++++++++--- pandatool/src/gtk-stats/gtkStatsGraph.h | 42 +-- pandatool/src/gtk-stats/gtkStatsLabel.cxx | 3 +- pandatool/src/gtk-stats/gtkStatsMonitor.cxx | 2 +- .../src/gtk-stats/gtkStatsStripChart.cxx | 277 ++++++++++++++++-- pandatool/src/gtk-stats/gtkStatsStripChart.h | 15 +- 7 files changed, 469 insertions(+), 90 deletions(-) diff --git a/pandatool/src/gtk-stats/Sources.pp b/pandatool/src/gtk-stats/Sources.pp index db98d6b637..d826df33c3 100644 --- a/pandatool/src/gtk-stats/Sources.pp +++ b/pandatool/src/gtk-stats/Sources.pp @@ -2,9 +2,9 @@ #define USE_PACKAGES net gtk #begin bin_target - // We rename TARGET to gtk-pstats on Windows, so it won't compete + // We rename TARGET to pstats-gtk on Windows, so it won't compete // with Windows-native pstats. - #define TARGET $[if $[WINDOWS_PLATFORM],gtk-pstats,pstats] + #define TARGET $[if $[WINDOWS_PLATFORM],pstats-gtk,pstats] #define LOCAL_LIBS \ progbase pstatserver #define OTHER_LIBS \ diff --git a/pandatool/src/gtk-stats/gtkStatsGraph.cxx b/pandatool/src/gtk-stats/gtkStatsGraph.cxx index 54e1e01143..35fba7bd93 100755 --- a/pandatool/src/gtk-stats/gtkStatsGraph.cxx +++ b/pandatool/src/gtk-stats/gtkStatsGraph.cxx @@ -49,33 +49,70 @@ GtkStatsGraph(GtkStatsMonitor *monitor, int thread_index) : _parent_window = NULL; _window = NULL; _graph_window = NULL; - // _sizewe_cursor = LoadCursor(NULL, IDC_SIZEWE); - // _hand_cursor = LoadCursor(NULL, IDC_HAND); + _scale_area = NULL; + + GtkWidget *parent_window = monitor->get_window(); + + GdkDisplay *display = gdk_drawable_get_display(parent_window->window); + _hand_cursor = gdk_cursor_new_for_display(display, GDK_HAND2); + _pixmap = 0; _pixmap_gc = 0; - _graph_left = 0; - _graph_top = 0; _pixmap_xsize = 0; _pixmap_ysize = 0; _window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - GtkWidget *parent_window = monitor->get_window(); gtk_window_set_transient_for(GTK_WINDOW(_window), GTK_WINDOW(parent_window)); gtk_window_set_destroy_with_parent(GTK_WINDOW(_window), TRUE); + gtk_widget_add_events(_window, + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK); g_signal_connect(G_OBJECT(_window), "delete_event", G_CALLBACK(window_delete_event), this); g_signal_connect(G_OBJECT(_window), "destroy", G_CALLBACK(window_destroy), this); + g_signal_connect(G_OBJECT(_window), "button_press_event", + G_CALLBACK(button_press_event_callback), this); + g_signal_connect(G_OBJECT(_window), "button_release_event", + G_CALLBACK(button_release_event_callback), this); + g_signal_connect(G_OBJECT(_window), "motion_notify_event", + G_CALLBACK(motion_notify_event_callback), this); _graph_window = gtk_drawing_area_new(); + gtk_widget_add_events(_graph_window, + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK); g_signal_connect(G_OBJECT(_graph_window), "expose_event", - G_CALLBACK(expose_event_callback), this); + G_CALLBACK(graph_expose_callback), this); g_signal_connect(G_OBJECT(_graph_window), "configure_event", - G_CALLBACK(configure_event_callback), this); + G_CALLBACK(configure_graph_callback), this); + g_signal_connect(G_OBJECT(_graph_window), "button_press_event", + G_CALLBACK(button_press_event_callback), this); + g_signal_connect(G_OBJECT(_graph_window), "button_release_event", + G_CALLBACK(button_release_event_callback), this); + g_signal_connect(G_OBJECT(_graph_window), "motion_notify_event", + G_CALLBACK(motion_notify_event_callback), this); - gtk_widget_set_size_request(_graph_window, 400, 100); + // A Frame to hold the graph. + GtkWidget *graph_frame = gtk_frame_new(NULL); + gtk_frame_set_shadow_type(GTK_FRAME(graph_frame), GTK_SHADOW_IN); + gtk_container_add(GTK_CONTAINER(graph_frame), _graph_window); + + // An HBox to hold the graph's frame, and the scale legend to the + // right of it. + _graph_hbox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(_graph_hbox), graph_frame, + TRUE, TRUE, 0); + + // An HPaned to hold the label stack and the graph hbox. + _hpaned = gtk_hpaned_new(); + gtk_container_add(GTK_CONTAINER(_window), _hpaned); + gtk_container_set_border_width(GTK_CONTAINER(_window), 8); + + gtk_paned_pack1(GTK_PANED(_hpaned), _label_stack.get_widget(), TRUE, TRUE); + gtk_paned_pack2(GTK_PANED(_hpaned), _graph_hbox, TRUE, TRUE); _drag_mode = DM_none; _potential_drag_mode = DM_none; @@ -106,15 +143,7 @@ GtkStatsGraph:: g_object_unref(gc); } - if (_graph_window != NULL) { - gtk_widget_destroy(_graph_window); - _graph_window = NULL; - } - - if (_window != NULL) { - gtk_widget_destroy(_window); - _window = NULL; - } + gtk_widget_destroy(_window); } //////////////////////////////////////////////////////////////////// @@ -208,10 +237,10 @@ set_pause(bool pause) { //////////////////////////////////////////////////////////////////// void GtkStatsGraph:: user_guide_bars_changed() { - /* - InvalidateRect(_window, NULL, TRUE); - InvalidateRect(_graph_window, NULL, TRUE); - */ + if (_scale_area != NULL) { + gtk_widget_queue_draw(_scale_area); + } + gtk_widget_queue_draw(_graph_window); } //////////////////////////////////////////////////////////////////// @@ -267,22 +296,27 @@ get_collector_gc(int collector_index) { return gc; } +//////////////////////////////////////////////////////////////////// +// Function: GtkStatsGraph::additional_graph_window_paint +// Access: Protected, Virtual +// Description: This is called during the servicing of expose_event; +// it gives a derived class opportunity to do some +// further painting into the graph window. +//////////////////////////////////////////////////////////////////// +void GtkStatsGraph:: +additional_graph_window_paint() { +} + //////////////////////////////////////////////////////////////////// // Function: GtkStatsGraph::consider_drag_start // Access: Protected, Virtual -// Description: Based on the mouse position within the window's -// client area, look for draggable things the mouse -// might be hovering over and return the apprioprate -// DragMode enum or DM_none if nothing is indicated. +// Description: Based on the mouse position within the graph window, +// look for draggable things the mouse might be hovering +// over and return the appropriate DragMode enum or +// DM_none if nothing is indicated. //////////////////////////////////////////////////////////////////// GtkStatsGraph::DragMode GtkStatsGraph:: -consider_drag_start(int mouse_x, int mouse_y, int width, int height) { - if (mouse_x >= _left_margin - 2 && mouse_x <= _left_margin + 2) { - return DM_left_margin; - } else if (mouse_x >= width - _right_margin - 2 && mouse_x <= width - _right_margin + 2) { - return DM_right_margin; - } - +consider_drag_start(int graph_x, int graph_y) { return DM_none; } @@ -298,6 +332,58 @@ set_drag_mode(GtkStatsGraph::DragMode drag_mode) { _drag_mode = drag_mode; } +//////////////////////////////////////////////////////////////////// +// Function: GtkStatsGraph::handle_button_press +// Access: Protected, Virtual +// Description: Called when the mouse button is depressed within the +// window, or any nested window. +//////////////////////////////////////////////////////////////////// +gboolean GtkStatsGraph:: +handle_button_press(GtkWidget *widget, int graph_x, int graph_y) { + if (_potential_drag_mode != DM_none) { + set_drag_mode(_potential_drag_mode); + _drag_start_x = graph_x; + _drag_start_y = graph_y; + // SetCapture(_window); + } + return TRUE; +} + +//////////////////////////////////////////////////////////////////// +// Function: GtkStatsGraph::handle_button_release +// Access: Protected, Virtual +// Description: Called when the mouse button is released within the +// window, or any nested window. +//////////////////////////////////////////////////////////////////// +gboolean GtkStatsGraph:: +handle_button_release(GtkWidget *widget, int graph_x, int graph_y) { + set_drag_mode(DM_none); + // ReleaseCapture(); + + return handle_motion(widget, graph_x, graph_y); +} + +//////////////////////////////////////////////////////////////////// +// Function: GtkStatsGraph::handle_motion +// Access: Protected, Virtual, Static +// Description: Called when the mouse is moved within the +// window, or any nested window. +//////////////////////////////////////////////////////////////////// +gboolean GtkStatsGraph:: +handle_motion(GtkWidget *widget, int graph_x, int graph_y) { + _potential_drag_mode = consider_drag_start(graph_x, graph_y); + + if (_potential_drag_mode == DM_guide_bar || + _drag_mode == DM_guide_bar) { + gdk_window_set_cursor(_window->window, _hand_cursor); + + } else { + gdk_window_set_cursor(_window->window, NULL); + } + + return TRUE; +} + //////////////////////////////////////////////////////////////////// // Function: GtkStatsGraph::setup_pixmap // Access: Private @@ -347,7 +433,7 @@ window_delete_event(GtkWidget *widget, GdkEvent *event, gpointer data) { } //////////////////////////////////////////////////////////////////// -// Function: GtkStatsGraph::window_delete_event +// Function: GtkStatsGraph::window_destroy // Access: Private, Static // Description: Callback when the window is destroyed by the system // (or by delete_event). @@ -359,12 +445,12 @@ window_destroy(GtkWidget *widget, gpointer data) { } //////////////////////////////////////////////////////////////////// -// Function: GtkStatsGraph::expose_event_callback +// Function: GtkStatsGraph::graph_expose_callback // Access: Private, Static // Description: Fills in the graph window. //////////////////////////////////////////////////////////////////// gboolean GtkStatsGraph:: -expose_event_callback(GtkWidget *widget, GdkEventExpose *event, gpointer data) { +graph_expose_callback(GtkWidget *widget, GdkEventExpose *event, gpointer data) { GtkStatsGraph *self = (GtkStatsGraph *)data; if (self->_pixmap != NULL) { @@ -373,17 +459,19 @@ expose_event_callback(GtkWidget *widget, GdkEventExpose *event, gpointer data) { self->_pixmap, 0, 0, 0, 0, self->_pixmap_xsize, self->_pixmap_ysize); } + + self->additional_graph_window_paint(); return TRUE; } //////////////////////////////////////////////////////////////////// -// Function: GtkStatsGraph::configure_event_callback +// Function: GtkStatsGraph::configure_graph_callback // Access: Private, Static // Description: Changes the size of the graph window //////////////////////////////////////////////////////////////////// gboolean GtkStatsGraph:: -configure_event_callback(GtkWidget *widget, GdkEventConfigure *event, +configure_graph_callback(GtkWidget *widget, GdkEventConfigure *event, gpointer data) { GtkStatsGraph *self = (GtkStatsGraph *)data; @@ -393,3 +481,57 @@ configure_event_callback(GtkWidget *widget, GdkEventConfigure *event, return TRUE; } + +//////////////////////////////////////////////////////////////////// +// Function: GtkStatsGraph::button_press_event_callback +// Access: Private, Static +// Description: Called when the mouse button is depressed within the +// graph window or main window. +//////////////////////////////////////////////////////////////////// +gboolean GtkStatsGraph:: +button_press_event_callback(GtkWidget *widget, GdkEventButton *event, + gpointer data) { + GtkStatsGraph *self = (GtkStatsGraph *)data; + int graph_x, graph_y; + gtk_widget_translate_coordinates(widget, self->_graph_window, + (int)event->x, (int)event->y, + &graph_x, &graph_y); + + return self->handle_button_press(widget, graph_x, graph_y); +} + +//////////////////////////////////////////////////////////////////// +// Function: GtkStatsGraph::button_release_event_callback +// Access: Private, Static +// Description: Called when the mouse button is released within the +// graph window or main window. +//////////////////////////////////////////////////////////////////// +gboolean GtkStatsGraph:: +button_release_event_callback(GtkWidget *widget, GdkEventButton *event, + gpointer data) { + GtkStatsGraph *self = (GtkStatsGraph *)data; + int graph_x, graph_y; + gtk_widget_translate_coordinates(widget, self->_graph_window, + (int)event->x, (int)event->y, + &graph_x, &graph_y); + + return self->handle_button_release(widget, graph_x, graph_y); +} + +//////////////////////////////////////////////////////////////////// +// Function: GtkStatsGraph::motion_notify_event_callback +// Access: Private, Static +// Description: Called when the mouse is moved within the +// graph window or main window. +//////////////////////////////////////////////////////////////////// +gboolean GtkStatsGraph:: +motion_notify_event_callback(GtkWidget *widget, GdkEventMotion *event, + gpointer data) { + GtkStatsGraph *self = (GtkStatsGraph *)data; + int graph_x, graph_y; + gtk_widget_translate_coordinates(widget, self->_graph_window, + (int)event->x, (int)event->y, + &graph_x, &graph_y); + + return self->handle_motion(widget, graph_x, graph_y); +} diff --git a/pandatool/src/gtk-stats/gtkStatsGraph.h b/pandatool/src/gtk-stats/gtkStatsGraph.h index 46fa0bae15..15ea508731 100755 --- a/pandatool/src/gtk-stats/gtkStatsGraph.h +++ b/pandatool/src/gtk-stats/gtkStatsGraph.h @@ -39,8 +39,6 @@ public: enum DragMode { DM_none, DM_scale, - DM_left_margin, - DM_right_margin, DM_guide_bar, DM_new_guide_bar, DM_sizing, @@ -68,14 +66,14 @@ protected: void close(); GdkGC *get_collector_gc(int collector_index); - /* - virtual void additional_window_paint(HDC hdc); - virtual void additional_graph_window_paint(HDC hdc); - */ - virtual DragMode consider_drag_start(int mouse_x, int mouse_y, - int width, int height); + virtual void additional_graph_window_paint(); + virtual DragMode consider_drag_start(int graph_x, int graph_y); virtual void set_drag_mode(DragMode drag_mode); + virtual gboolean handle_button_press(GtkWidget *widget, int graph_x, int graph_y); + virtual gboolean handle_button_release(GtkWidget *widget, int graph_x, int graph_y); + virtual gboolean handle_motion(GtkWidget *widget, int graph_x, int graph_y); + protected: // Table of GC's for our various collectors. typedef pmap Brushes; @@ -86,20 +84,16 @@ protected: GtkWidget *_parent_window; GtkWidget *_window; GtkWidget *_graph_window; + GtkWidget *_graph_hbox; + GtkWidget *_hpaned; + GtkWidget *_scale_area; GtkStatsLabelStack _label_stack; - /* - HCURSOR _sizewe_cursor; - HCURSOR _hand_cursor; - */ + GdkCursor *_hand_cursor; GdkPixmap *_pixmap; GdkGC *_pixmap_gc; - - int _graph_left, _graph_top; int _pixmap_xsize, _pixmap_ysize; - int _left_margin, _right_margin; - int _top_margin, _bottom_margin; /* COLORREF _dark_color; @@ -127,15 +121,25 @@ protected: private: void setup_pixmap(int xsize, int ysize); void release_pixmap(); - void create_graph_window(); static gboolean window_delete_event(GtkWidget *widget, GdkEvent *event, gpointer data); static void window_destroy(GtkWidget *widget, gpointer data); - static gboolean expose_event_callback(GtkWidget *widget, + static gboolean graph_expose_callback(GtkWidget *widget, GdkEventExpose *event, gpointer data); - static gboolean configure_event_callback(GtkWidget *widget, + static gboolean configure_graph_callback(GtkWidget *widget, GdkEventConfigure *event, gpointer data); + +protected: + static gboolean button_press_event_callback(GtkWidget *widget, + GdkEventButton *event, + gpointer data); + static gboolean button_release_event_callback(GtkWidget *widget, + GdkEventButton *event, + gpointer data); + static gboolean motion_notify_event_callback(GtkWidget *widget, + GdkEventMotion *event, + gpointer data); }; #endif diff --git a/pandatool/src/gtk-stats/gtkStatsLabel.cxx b/pandatool/src/gtk-stats/gtkStatsLabel.cxx index 853920bcbe..0780dbaf41 100644 --- a/pandatool/src/gtk-stats/gtkStatsLabel.cxx +++ b/pandatool/src/gtk-stats/gtkStatsLabel.cxx @@ -223,7 +223,8 @@ leave_notify_event_callback(GtkWidget *widget, GdkEventCrossing *event, //////////////////////////////////////////////////////////////////// // Function: GtkStatsLabel::button_press_event_callback // Access: Private, Static -// Description: Called when the mouse leaves the label region +// Description: Called when the mouse button is depressed within the +// label. //////////////////////////////////////////////////////////////////// gboolean GtkStatsLabel:: button_press_event_callback(GtkWidget *widget, GdkEventButton *event, diff --git a/pandatool/src/gtk-stats/gtkStatsMonitor.cxx b/pandatool/src/gtk-stats/gtkStatsMonitor.cxx index 113bfaa490..30cd297bad 100644 --- a/pandatool/src/gtk-stats/gtkStatsMonitor.cxx +++ b/pandatool/src/gtk-stats/gtkStatsMonitor.cxx @@ -550,7 +550,7 @@ window_delete_event(GtkWidget *widget, GdkEvent *event, gpointer data) { } //////////////////////////////////////////////////////////////////// -// Function: GtkStatsMonitor::window_delete_event +// Function: GtkStatsMonitor::window_destroy // Access: Private, Static // Description: Callback when the window is destroyed by the system // (or by delete_event). diff --git a/pandatool/src/gtk-stats/gtkStatsStripChart.cxx b/pandatool/src/gtk-stats/gtkStatsStripChart.cxx index c3c7468bd5..7ab345e9e3 100644 --- a/pandatool/src/gtk-stats/gtkStatsStripChart.cxx +++ b/pandatool/src/gtk-stats/gtkStatsStripChart.cxx @@ -41,11 +41,6 @@ GtkStatsStripChart(GtkStatsMonitor *monitor, int thread_index, { _brush_origin = 0; - _left_margin = 96; - _right_margin = 32; - _top_margin = 16; - _bottom_margin = 8; - if (show_level) { // If it's a level-type graph, show the appropriate units. if (_unit_name.empty()) { @@ -61,17 +56,25 @@ GtkStatsStripChart(GtkStatsMonitor *monitor, int thread_index, _smooth_check_box = 0; - GtkWidget *hbox = gtk_hbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(hbox), _label_stack.get_widget(), + // Add a DrawingArea widget to display all of the scale units. + _scale_area = gtk_drawing_area_new(); + g_signal_connect(G_OBJECT(_scale_area), "expose_event", + G_CALLBACK(expose_event_callback), this); + gtk_box_pack_start(GTK_BOX(_graph_hbox), _scale_area, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(hbox), _graph_window, - TRUE, TRUE, 0); + gtk_widget_set_size_request(_scale_area, 40, 0); - gtk_container_add(GTK_CONTAINER(_window), hbox); + + gtk_widget_set_size_request(_graph_window, 400, 100); gtk_widget_show_all(_window); gtk_widget_show(_window); + // Allow the window to be resized as small as the user likes. We + // have to do this after the window has been shown; otherwise, it + // will affect the window's initial size. + gtk_widget_set_size_request(_window, 0, 0); + clear_region(); } @@ -238,6 +241,7 @@ set_vertical_scale(float value_height) { PStatStripChart::set_vertical_scale(value_height); gtk_widget_queue_draw(_graph_window); + gtk_widget_queue_draw(_scale_area); } //////////////////////////////////////////////////////////////////// @@ -319,14 +323,13 @@ draw_slice(int x, int w, const PStatStripChart::FrameData &fdata) { if (overall_time > get_vertical_scale()) { // Off the top. Go ahead and clamp it by hand, in case it's so // far off the top we'd overflow the 16-bit pixel value. - gdk_draw_rectangle(_pixmap, gc, TRUE, x, 0, w + 1, y); - + gdk_draw_rectangle(_pixmap, gc, TRUE, x, 0, w, y); // And we can consider ourselves done now. return; } int top_y = height_to_pixel(overall_time); - gdk_draw_rectangle(_pixmap, gc, TRUE, x, top_y, w + 1, y); + gdk_draw_rectangle(_pixmap, gc, TRUE, x, top_y, w, y - top_y); y = top_y; } } @@ -367,7 +370,7 @@ end_draw(int from_x, int to_x) { // Draw in the guide bars. int num_guide_bars = get_num_guide_bars(); for (int i = 0; i < num_guide_bars; i++) { - draw_guide_bar(from_x, to_x, get_guide_bar(i)); + draw_guide_bar(_pixmap, from_x, to_x, get_guide_bar(i)); } GdkRectangle rect = { @@ -376,20 +379,35 @@ end_draw(int from_x, int to_x) { gdk_window_invalidate_rect(_graph_window->window, &rect, FALSE); } +//////////////////////////////////////////////////////////////////// +// Function: GtkStatsStripChart::additional_graph_window_paint +// Access: Protected, Virtual +// Description: This is called during the servicing of expose_event; +// it gives a derived class opportunity to do some +// further painting into the graph window. +//////////////////////////////////////////////////////////////////// +void GtkStatsStripChart:: +additional_graph_window_paint() { + int num_user_guide_bars = get_num_user_guide_bars(); + for (int i = 0; i < num_user_guide_bars; i++) { + draw_guide_bar(_graph_window->window, 0, get_xsize(), get_user_guide_bar(i)); + } +} + //////////////////////////////////////////////////////////////////// // Function: GtkStatsStripChart::consider_drag_start // Access: Protected, Virtual -// Description: Based on the mouse position within the window's -// client area, look for draggable things the mouse -// might be hovering over and return the apprioprate -// DragMode enum or DM_none if nothing is indicated. +// Description: Based on the mouse position within the graph window, +// look for draggable things the mouse might be hovering +// over and return the appropriate DragMode enum or +// DM_none if nothing is indicated. //////////////////////////////////////////////////////////////////// GtkStatsGraph::DragMode GtkStatsStripChart:: -consider_drag_start(int mouse_x, int mouse_y, int width, int height) { - if (mouse_x >= _graph_left && mouse_x < _graph_left + get_xsize()) { - if (mouse_y >= _graph_top && mouse_y < _graph_top + get_ysize()) { +consider_drag_start(int graph_x, int graph_y) { + if (graph_x >= 0 && graph_x < get_xsize()) { + if (graph_y >= 0 && graph_y < get_ysize()) { // See if the mouse is over a user-defined guide bar. - int y = mouse_y - _graph_top; + int y = graph_y; float from_height = pixel_to_height(y + 2); float to_height = pixel_to_height(y - 2); _drag_guide_bar = find_user_guide_bar(from_height, to_height); @@ -404,7 +422,7 @@ consider_drag_start(int mouse_x, int mouse_y, int width, int height) { } } - return GtkStatsGraph::consider_drag_start(mouse_x, mouse_y, width, height); + return GtkStatsGraph::consider_drag_start(graph_x, graph_y); } //////////////////////////////////////////////////////////////////// @@ -420,8 +438,6 @@ set_drag_mode(GtkStatsGraph::DragMode drag_mode) { switch (_drag_mode) { case DM_scale: - case DM_left_margin: - case DM_right_margin: case DM_sizing: // Disable smoothing for these expensive operations. set_average_mode(false); @@ -438,6 +454,110 @@ set_drag_mode(GtkStatsGraph::DragMode drag_mode) { } } +//////////////////////////////////////////////////////////////////// +// Function: GtkStatsStripChart::handle_button_press +// Access: Protected, Virtual +// Description: Called when the mouse button is depressed within the +// graph window. +//////////////////////////////////////////////////////////////////// +gboolean GtkStatsStripChart:: +handle_button_press(GtkWidget *widget, int graph_x, int graph_y) { + if (_potential_drag_mode == DM_none) { + set_drag_mode(DM_scale); + _drag_scale_start = pixel_to_height(graph_y); + //SetCapture(_graph_window); + return TRUE; + + } else if (_potential_drag_mode == DM_guide_bar && _drag_guide_bar >= 0) { + set_drag_mode(DM_guide_bar); + _drag_start_y = graph_y; + //SetCapture(_graph_window); + return TRUE; + } + + return GtkStatsGraph::handle_button_press(widget, graph_x, graph_y); +} + +//////////////////////////////////////////////////////////////////// +// Function: GtkStatsStripChart::handle_button_release +// Access: Protected, Virtual +// Description: Called when the mouse button is released within the +// graph window. +//////////////////////////////////////////////////////////////////// +gboolean GtkStatsStripChart:: +handle_button_release(GtkWidget *widget, int graph_x, int graph_y) { + if (_drag_mode == DM_scale) { + set_drag_mode(DM_none); + //ReleaseCapture(); + return handle_motion(widget, graph_x, graph_y); + + } else if (_drag_mode == DM_guide_bar) { + if (graph_y < 0 || graph_y >= get_ysize()) { + remove_user_guide_bar(_drag_guide_bar); + } else { + move_user_guide_bar(_drag_guide_bar, pixel_to_height(graph_y)); + } + set_drag_mode(DM_none); + //ReleaseCapture(); + return handle_motion(widget, graph_x, graph_y); + } + + return GtkStatsGraph::handle_button_release(widget, graph_x, graph_y); +} + +//////////////////////////////////////////////////////////////////// +// Function: GtkStatsStripChart::ns_motion_notify_event_callback +// Access: Protected, Virtual +// Description: Called when the mouse is moved within the +// graph window. +//////////////////////////////////////////////////////////////////// +gboolean GtkStatsStripChart:: +handle_motion(GtkWidget *widget, int graph_x, int graph_y) { + if (_drag_mode == DM_none && _potential_drag_mode == DM_none) { + // When the mouse is over a color bar, highlight it. + _label_stack.highlight_label(get_collector_under_pixel(graph_x, graph_y)); + + /* + // Now we want to get a WM_MOUSELEAVE when the mouse leaves the + // graph window. + TRACKMOUSEEVENT tme = { + sizeof(TRACKMOUSEEVENT), + TME_LEAVE, + _graph_window, + 0 + }; + TrackMouseEvent(&tme); + */ + + } else { + // If the mouse is in some drag mode, stop highlighting. + _label_stack.highlight_label(-1); + } + + if (_drag_mode == DM_scale) { + float ratio = 1.0f - ((float)graph_y / (float)get_ysize()); + if (ratio > 0.0f) { + set_vertical_scale(_drag_scale_start / ratio); + } + return TRUE; + + } else if (_drag_mode == DM_new_guide_bar) { + // We haven't created the new guide bar yet; we won't until the + // mouse comes within the graph's region. + if (graph_y >= 0 && graph_y < get_ysize()) { + set_drag_mode(DM_guide_bar); + _drag_guide_bar = add_user_guide_bar(pixel_to_height(graph_y)); + return TRUE; + } + + } else if (_drag_mode == DM_guide_bar) { + move_user_guide_bar(_drag_guide_bar, pixel_to_height(graph_y)); + return TRUE; + } + + return GtkStatsGraph::handle_motion(widget, graph_x, graph_y); +} + //////////////////////////////////////////////////////////////////// // Function: GtkStatsStripChart::draw_guide_bar // Access: Private @@ -445,7 +565,7 @@ set_drag_mode(GtkStatsGraph::DragMode drag_mode) { // graph. //////////////////////////////////////////////////////////////////// void GtkStatsStripChart:: -draw_guide_bar(int from_x, int to_x, +draw_guide_bar(GdkDrawable *surface, int from_x, int to_x, const PStatGraph::GuideBar &bar) { int y = height_to_pixel(bar._height); @@ -464,6 +584,109 @@ draw_guide_bar(int from_x, int to_x, gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_dark_gray); break; } - gdk_draw_line(_pixmap, _pixmap_gc, from_x, y, to_x, y); + gdk_draw_line(surface, _pixmap_gc, from_x, y, to_x, y); } } + +//////////////////////////////////////////////////////////////////// +// Function: GtkStatsStripChart::draw_guide_labels +// Access: Private +// Description: This is called during the servicing of expose_event. +//////////////////////////////////////////////////////////////////// +void GtkStatsStripChart:: +draw_guide_labels() { + // Draw in the labels for the guide bars. + int last_y = -100; + + int i; + int num_guide_bars = get_num_guide_bars(); + for (i = 0; i < num_guide_bars; i++) { + last_y = draw_guide_label(get_guide_bar(i), last_y); + } + + GuideBar top_value = make_guide_bar(get_vertical_scale()); + draw_guide_label(top_value, last_y); + + last_y = -100; + int num_user_guide_bars = get_num_user_guide_bars(); + for (i = 0; i < num_user_guide_bars; i++) { + last_y = draw_guide_label(get_user_guide_bar(i), last_y); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: GtkStatsStripChart::draw_guide_label +// Access: Private +// Description: Draws the text for the indicated guide bar label to +// the right of the graph, unless it would overlap with +// the indicated last label, whose top pixel value is +// given. Returns the top pixel value of the new label. +//////////////////////////////////////////////////////////////////// +int GtkStatsStripChart:: +draw_guide_label(const PStatGraph::GuideBar &bar, int last_y) { + GdkGC *gc = gdk_gc_new(_scale_area->window); + + switch (bar._style) { + case GBS_target: + gdk_gc_set_rgb_fg_color(gc, &rgb_light_gray); + break; + + case GBS_user: + gdk_gc_set_rgb_fg_color(gc, &rgb_user_guide_bar); + break; + + case GBS_normal: + gdk_gc_set_rgb_fg_color(gc, &rgb_dark_gray); + break; + } + + int y = height_to_pixel(bar._height); + const string &label = bar._label; + + PangoLayout *layout = gtk_widget_create_pango_layout(_window, label.c_str()); + int width, height; + pango_layout_get_pixel_size(layout, &width, &height); + + if (bar._style != GBS_user) { + float from_height = pixel_to_height(y + height); + float to_height = pixel_to_height(y - height); + if (find_user_guide_bar(from_height, to_height) >= 0) { + // Omit the label: there's a user-defined guide bar in the same space. + g_object_unref(layout); + g_object_unref(gc); + return last_y; + } + } + + // Now convert our y to a coordinate within our drawing area. + int junk_x; + + // The y coordinate comes from the graph_window. + gtk_widget_translate_coordinates(_graph_window, _scale_area, + 0, y, + &junk_x, &y); + + int this_y = y - height / 2; + if (y >= 0 && y <= _scale_area->allocation.height && + (last_y < this_y || last_y > this_y + height)) { + gdk_draw_layout(_scale_area->window, gc, 0, this_y, layout); + last_y = this_y; + } + + g_object_unref(layout); + g_object_unref(gc); + return last_y; +} + +//////////////////////////////////////////////////////////////////// +// Function: GtkStatsStripChart::expose_event_callback +// Access: Private, Static +// Description: Draws in the scale labels. +//////////////////////////////////////////////////////////////////// +gboolean GtkStatsStripChart:: +expose_event_callback(GtkWidget *widget, GdkEventExpose *event, gpointer data) { + GtkStatsStripChart *self = (GtkStatsStripChart *)data; + self->draw_guide_labels(); + + return TRUE; +} diff --git a/pandatool/src/gtk-stats/gtkStatsStripChart.h b/pandatool/src/gtk-stats/gtkStatsStripChart.h index 760b865654..5e8c088923 100644 --- a/pandatool/src/gtk-stats/gtkStatsStripChart.h +++ b/pandatool/src/gtk-stats/gtkStatsStripChart.h @@ -60,13 +60,22 @@ protected: virtual void draw_cursor(int x); virtual void end_draw(int from_x, int to_x); - virtual DragMode consider_drag_start(int mouse_x, int mouse_y, - int width, int height); + virtual void additional_graph_window_paint(); + virtual DragMode consider_drag_start(int graph_x, int graph_y); virtual void set_drag_mode(DragMode drag_mode); + virtual gboolean handle_button_press(GtkWidget *widget, int graph_x, int graph_y); + virtual gboolean handle_button_release(GtkWidget *widget, int graph_x, int graph_y); + virtual gboolean handle_motion(GtkWidget *widget, int graph_x, int graph_y); + private: - void draw_guide_bar(int from_x, int to_x, + void draw_guide_bar(GdkDrawable *surface, int from_x, int to_x, const PStatGraph::GuideBar &bar); + void draw_guide_labels(); + int draw_guide_label(const PStatGraph::GuideBar &bar, int last_y); + + static gboolean expose_event_callback(GtkWidget *widget, + GdkEventExpose *event, gpointer data); private: