From d293d53136fa7e6e7eda510847145edf4d3d7f55 Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Tue, 1 Dec 2009 12:26:59 +0100 Subject: Add hover text to the graph. When the graph display is paused, leaving the mouse stationary over the graph will display the data point under the pointer. * grapher/CairoWidget.hxx (CairoTextBox): new class (CairoWidget, CairoPlayButton): refector some play button-specific things from CairoWidget to CairoPlayButton. * grapher/CairoWidget.cxx (CairoTextBox::draw): new function. * grapher/GraphWidget.hxx (GraphWidget): new members for supporting hover text. * grapher/GraphWidget.cxx (on_motion_notify_event): Set up hover text box. (establishHoverTimeout, onHoverTimeout, getGraphUnderPoint): new functions. --- grapher/GraphWidget.cxx | 108 +++++++++++++++++++++++++++++++----------------- 1 file changed, 70 insertions(+), 38 deletions(-) (limited to 'grapher/GraphWidget.cxx') diff --git a/grapher/GraphWidget.cxx b/grapher/GraphWidget.cxx index cee1a6d2..9a203d87 100644 --- a/grapher/GraphWidget.cxx +++ b/grapher/GraphWidget.cxx @@ -1,8 +1,10 @@ #include #include +#include #include #include +#include #include #include @@ -19,7 +21,8 @@ namespace systemtap GraphWidget::GraphWidget() - : _trackingDrag(false), _width(600), _height(200) + : _trackingDrag(false), _width(600), _height(200), _mouseX(0.0), + _mouseY(0.0) { add_events(Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::SCROLL_MASK); @@ -104,16 +107,6 @@ namespace systemtap return true; Cairo::RefPtr cr = window->create_cairo_context(); -#if 0 - if(event && !_autoScaling) - { - // clip to the area indicated by the expose event so that we only - // redraw the portion of the window that needs to be redrawn - cr->rectangle(event->area.x, event->area.y, - event->area.width, event->area.height); - cr->clip(); - } -#endif cr->save(); cr->set_source_rgba(0.0, 0.0, 0.0, 1.0); cr->paint(); @@ -126,28 +119,21 @@ namespace systemtap (*g)->draw(cr); cr->restore(); } + if (_hoverText && _hoverText->isVisible()) + _hoverText->draw(cr); return true; } bool GraphWidget::on_button_press_event(GdkEventButton* event) { - for (GraphList::iterator g = _graphs.begin(); g != _graphs.end(); ++g) + shared_ptr g = getGraphUnderPoint(event->x, event->y); + if (g) { - if (event->x >= (*g)->_graphX - && event->x < (*g)->_graphX + (*g)->_graphWidth - && event->y >= (*g)->_graphY - && event->y < (*g)->_graphY + (*g)->_graphHeight) + _activeGraph = g; + if (event->button == 3) { - _activeGraph = *g; - if (event->button == 3) - { - _dataDialog->show(); - return true; - } - else - { - break; - } + _dataDialog->show(); + return true; } } if (!_activeGraph) @@ -171,6 +157,7 @@ namespace systemtap _dragOriginY = event->y; _dragOrigLeft = _activeGraph->_left; _dragOrigRight = _activeGraph->_right; + establishHoverTimeout(); } return true; } @@ -191,27 +178,25 @@ namespace systemtap Glib::RefPtr win = get_window(); if(!win) return true; - double x = 0.0; - double y = 0.0; - // XXX Hint - if (event->is_hint) - { - } - else - { - x = event->x; - y = event->y; - } + _mouseX = event->x; + _mouseY = event->y; if (_trackingDrag && _activeGraph) { Gtk::Allocation allocation = get_allocation(); const int width = allocation.get_width(); - double motion = (x - _dragOriginX) / (double) width; + double motion = (_mouseX - _dragOriginX) / (double) width; double increment = motion * (_dragOrigLeft - _dragOrigRight); _activeGraph->_left = _dragOrigLeft + increment; _activeGraph->_right = _dragOrigRight + increment; queue_draw(); } + if (_hoverText && _hoverText->isVisible()) + { + _hoverText->setVisible(false); + queue_draw(); + } + establishHoverTimeout(); + return true; } @@ -282,4 +267,51 @@ namespace systemtap row[_dataColumns._graphData] = *itr; } } + + bool GraphWidget::onHoverTimeout() + { + shared_ptr g = getGraphUnderPoint(_mouseX, _mouseY); + if (g && !g->_autoScrolling) + { + if (!_hoverText) + _hoverText = shared_ptr(new CairoTextBox()); + _hoverText->setOrigin(_mouseX + 5, _mouseY - 5); + int64_t t = g->getTimeAtPoint(_mouseX); + Graph::DatasetList& dataSets = g->getDatasets(); + if (!dataSets.empty()) + { + shared_ptr gdbase = dataSets[0]; + GraphDataBase::TimeList::iterator itime + = std::lower_bound(gdbase->times.begin(), gdbase->times.end(), t); + if (itime != gdbase->times.end()) { + size_t index = distance(gdbase->times.begin(), itime); + _hoverText->contents = gdbase->elementAsString(index); + _hoverText->setVisible(true); + queue_draw(); + } + } + } + return false; + } + + shared_ptr GraphWidget::getGraphUnderPoint(double x, double y) + { + for (GraphList::iterator g = _graphs.begin(); g != _graphs.end(); ++g) + { + if (x >= (*g)->_graphX + && x < (*g)->_graphX + (*g)->_graphWidth + && y >= (*g)->_graphY + && y < (*g)->_graphY + (*g)->_graphHeight) + return *g; + } + return shared_ptr(); + } + + void GraphWidget::establishHoverTimeout() + { + if (_hover_timeout_connection.connected()) + _hover_timeout_connection.disconnect(); + _hover_timeout_connection = Glib::signal_timeout() + .connect(sigc::mem_fun(*this, &GraphWidget::onHoverTimeout), 1000); + } } -- cgit