diff options
author | Tim Moore <timoore@redhat.com> | 2009-07-27 12:46:30 +0200 |
---|---|---|
committer | Tim Moore <timoore@redhat.com> | 2009-07-28 11:21:15 +0200 |
commit | 364ad890e341bb60ae169af69933a382d4bf9f81 (patch) | |
tree | 4b2fb5eb5644bdebc38b935077fa96ace8d831c5 /grapher/GraphWidget.cxx | |
parent | a030ced8c0b8109ba7b23bbbc65deddf88154a2f (diff) | |
download | systemtap-steved-364ad890e341bb60ae169af69933a382d4bf9f81.tar.gz systemtap-steved-364ad890e341bb60ae169af69933a382d4bf9f81.tar.xz systemtap-steved-364ad890e341bb60ae169af69933a382d4bf9f81.zip |
Support for presenting multiple graphs
* grapher/Graph.hxx: New file; class for single graph display.
* grapher/Graph.cxx: New file.
* grapher/GraphData.hxx: Associate title and axis labels with graph
data and not a graph display.
* grapher/GraphWidget.hxx: Move graph-related members to Graph class.
* grapher/GraphWidget.cxx (getExtents, setExtents): Move to Graph
class
(on_expose_event): Move graph rendering to Graph.
(on_button_press_event): Delegate to Graph.
(on_motion_notify_event, on_scroll_event): Modify "active" graph.
* grapher/StapParser.cxx (findTaggedValue): New parsing helper
function.
(io_callback): Support new syntax where properties are attached to
graph data and not the entire graph.
* grapher/grapher.cxx (GrapherWindow): Don't set graph values.
* grapher/Makefile.am: Add Graph.cxx.
* testsuite/systemtap.examples/general/grapher.stp: New property syntax.
Diffstat (limited to 'grapher/GraphWidget.cxx')
-rw-r--r-- | grapher/GraphWidget.cxx | 294 |
1 files changed, 53 insertions, 241 deletions
diff --git a/grapher/GraphWidget.cxx b/grapher/GraphWidget.cxx index d62ec4f3..5b0d1b1c 100644 --- a/grapher/GraphWidget.cxx +++ b/grapher/GraphWidget.cxx @@ -1,21 +1,18 @@ #include <algorithm> #include <ctime> #include <math.h> -#include <sstream> -#include <iostream> -#include <iomanip> + #include <cairomm/context.h> #include "GraphWidget.hxx" #include "CairoWidget.hxx" namespace systemtap { - using std::string; + using namespace std; + using namespace std::tr1; GraphWidget::GraphWidget() - : _left(0.0), _right(1.0), _top(1.0), _bottom(0.0), _lineWidth(10), - _autoScaling(true), _autoScrolling(true), _zoomFactor(1.0), - _trackingDrag(false), _playButton(new CairoPlayButton) + : _trackingDrag(false) { add_events(Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::SCROLL_MASK); @@ -34,33 +31,20 @@ namespace systemtap false); signal_scroll_event() .connect(sigc::mem_fun(*this, &GraphWidget::on_scroll_event), false); + // Temporary testing of multiple graphs + shared_ptr<Graph> graph(new Graph); + graph->_graphHeight = 180; + graph->_graphWidth = 580; + _graphs.push_back(graph); } - void GraphWidget::getExtents(double& left, double& right, double& top, - double& bottom) const - { - left = _left; - right = _right; - top = _top; - bottom = _bottom; - } - - void GraphWidget::setExtents(double left, double right, double top, - double bottom) - { - _left = left; - _right = right; - _top = top; - _bottom = bottom; - - } GraphWidget::~GraphWidget() { } void GraphWidget::addGraphData(std::tr1::shared_ptr<GraphDataBase> data) { - _datasets.push_back(data); + _graphs[0]->addGraphData(data); } bool GraphWidget::on_expose_event(GdkEventExpose* event) @@ -78,6 +62,7 @@ namespace systemtap const int height = graphHeight - 20; Cairo::RefPtr<Cairo::Context> cr = window->create_cairo_context(); +#if 0 if(event && !_autoScaling) { // clip to the area indicated by the expose event so that we only @@ -86,233 +71,51 @@ namespace systemtap event->area.width, event->area.height); cr->clip(); } - if (_autoScaling) - { - // line separation - int linesPossible = width / ((int)_lineWidth + 2); - // Find latest time. - double latestTime = 0; - for (DatasetList::iterator ditr = _datasets.begin(), - de = _datasets.end(); - ditr != de; - ++ditr) - { - if (!(*ditr)->times.empty()) - { - double lastDataTime = (*ditr)->times.back(); - if (lastDataTime > latestTime) - latestTime = lastDataTime; - } - } - double minDiff = 0.0; - double maxTotal = 0.0; - for (DatasetList::iterator ditr = _datasets.begin(), - de = _datasets.end(); - ditr != de; - ++ditr) - { - GraphDataBase::TimeList& gtimes = (*ditr)->times; - if (gtimes.size() <= 1) - continue; - double totalDiff = 0.0; - for (GraphDataBase::TimeList::reverse_iterator ritr = gtimes.rbegin(), - re = gtimes.rend(); - ritr + 1 != gtimes.rend(); - ritr++) - { - double timeDiff = *ritr - *(ritr + 1); - if (timeDiff < minDiff || (timeDiff != 0 && minDiff == 0)) - minDiff = timeDiff; - if (minDiff != 0 - && (totalDiff + timeDiff) / minDiff > linesPossible) - break; - totalDiff += timeDiff; - } - if (totalDiff > maxTotal) - maxTotal = totalDiff; - } - // Now we have a global scale. - _right = latestTime; - if (maxTotal != 0) - _left = latestTime - maxTotal; - else - _left = _right - 1.0; - } - cr->save(); - double horizScale = _zoomFactor * width / ( _right - _left); - cr->translate(20.0, 0.0); - cr->set_line_width(_lineWidth); +#endif cr->save(); cr->set_source_rgba(0.0, 0.0, 0.0, 1.0); cr->paint(); - cr->restore(); - - for (DatasetList::iterator itr = _datasets.begin(), e = _datasets.end(); - itr != e; - ++itr) - { - std::tr1::shared_ptr<GraphData<double> > realData - = std::tr1::dynamic_pointer_cast<GraphData<double> >(*itr); - std::tr1::shared_ptr<GraphData<string> > stringData - = std::tr1::dynamic_pointer_cast<GraphData<string> >(*itr); - cr->save(); - cr->translate(0.0, height); - cr->scale(1.0, -1.0); - GraphDataBase::TimeList::iterator lower - = std::lower_bound((*itr)->times.begin(), (*itr)->times.end(), _left); - GraphDataBase::TimeList::iterator upper - = std::upper_bound((*itr)->times.begin(), (*itr)->times.end(), - _right); - // event bar - if ((*itr)->style == GraphDataBase::EVENT) - { - double eventHeight = height * ((*itr)->scale / 100.0); - cr->save(); - cr->set_line_width(3 * _lineWidth); - cr->set_source_rgba((*itr)->color[0], (*itr)->color[1], - (*itr)->color[2], .33); - cr->move_to(0, eventHeight); - cr->line_to(width, eventHeight); - cr->stroke(); - cr->restore(); - } - for (GraphDataBase::TimeList::iterator ditr = lower, de = upper; - ditr != de; - ++ditr) - { - size_t dataIndex = ditr - (*itr)->times.begin(); - cr->set_source_rgba((*itr)->color[0], (*itr)->color[1], - (*itr)->color[2], 1.0); - if ((*itr)->style == GraphDataBase::BAR && realData) - { - cr->move_to((*ditr - _left) * horizScale, 0); - cr->line_to((*ditr - _left) * horizScale, - realData->data[dataIndex] * height / (*itr)->scale); - cr->stroke(); - } - else if ((*itr)->style == GraphDataBase::DOT && realData) - { - cr->arc((*ditr - _left) * horizScale, - realData->data[dataIndex] * height / (*itr)->scale, - _lineWidth / 2.0, 0.0, M_PI * 2.0); - cr->fill(); - } - else if ((*itr)->style == GraphDataBase::EVENT && stringData) - { - double eventHeight = height * ((*itr)->scale / 100.0); - cr->save(); - cr->select_font_face("Sans", Cairo::FONT_SLANT_NORMAL, - Cairo::FONT_WEIGHT_NORMAL); - cr->set_font_size(12.0); - cr->save(); - cr->scale(1.0, -1.0); - cr->move_to((*ditr - _left) * horizScale, - -eventHeight -3.0 * _lineWidth - 2.0); - cr->show_text(stringData->data[dataIndex]); - cr->restore(); - cr->rectangle((*ditr - _left) * horizScale - 1.5 * _lineWidth, - eventHeight - 1.5 * _lineWidth, - 3.0 * _lineWidth, 3.0 * _lineWidth); - cr->fill(); - cr->restore(); - } - } - cr->restore(); - } - cr->restore(); - cr->save(); - cr->select_font_face("Sans", Cairo::FONT_SLANT_NORMAL, - Cairo::FONT_WEIGHT_BOLD); - cr->set_font_size(14.0); - cr->set_source_rgba(1.0, 1.0, 1.0, .8); - - if (!_title.empty()) - { - cr->move_to(20.0, 20.0); - cr->show_text(_title); - } - if (!_xAxisText.empty()) - { - cr->move_to(10.0, graphHeight - 5); - cr->show_text(_xAxisText); - } - if (!_yAxisText.empty()) + for (GraphList::iterator g = _graphs.begin(); g != _graphs.end(); ++g) { cr->save(); - cr->translate(10.0, height - 10.0); - cr->rotate(-M_PI / 2.0); - cr->move_to(10.0, 0.0); - cr->show_text(_yAxisText); + cr->translate((*g)->_graphX, (*g)->_graphY); + (*g)->draw(cr); cr->restore(); } - cr->restore(); - // Draw axes - double diff = _right - _left; - double majorUnit = pow(10.0, floor(log(diff) / log(10.0))); - double startTime = ceil(_left / majorUnit) * majorUnit; - cr->save(); - cr->set_source_rgba(1.0, 1.0, 1.0, .9); - cr->set_line_cap(Cairo::LINE_CAP_BUTT); - cr->set_line_width(_lineWidth); - cr->select_font_face("Sans", Cairo::FONT_SLANT_NORMAL, - Cairo::FONT_WEIGHT_NORMAL); - cr->set_font_size(10.0); - cr->move_to(20.0, 0.0); - cr->line_to(20.0, height); - cr->move_to(20.0, height); - cr->line_to(graphWidth, height); - cr->stroke(); - std::valarray<double> dash(1); - dash[0] = height / 10; - cr->set_dash(dash, 0.0); - double prevTextAdvance = 0; - for (double tickVal = startTime; tickVal <= _right; tickVal += majorUnit) - { - double x = (tickVal - _left) * horizScale + 20.0; - cr->move_to(x, 0.0); - cr->line_to(x, height); - cr->move_to(x, graphHeight - 5); - std::ostringstream stream; - stream << std::fixed << std::setprecision(0) << tickVal; - Cairo::TextExtents extents; - cr->get_text_extents(stream.str(), extents); - // Room for this label? - if (x + extents.x_bearing > prevTextAdvance) - { - cr->show_text(stream.str()); - prevTextAdvance = x + extents.x_advance; - } - } - cr->stroke(); - cr->restore(); - - if (!_autoScrolling) - { - _playButton->setVisible(true); - _playButton->setOrigin(width / 2 - 25, .875 * height - 50); - _playButton->draw(cr); - } - return true; } bool GraphWidget::on_button_press_event(GdkEventButton* event) { - if (!_autoScrolling && _playButton->containsPoint(event->x, event->y)) + for (GraphList::iterator g = _graphs.begin(); g != _graphs.end(); ++g) + { + if (event->x >= (*g)->_graphX + && event->x < (*g)->_graphX + (*g)->_graphWidth + && event->y >= (*g)->_graphY + && event->y < (*g)->_graphY + (*g)->_graphHeight) + { + _activeGraph = *g; + break; + } + } + if (!_activeGraph) + return true; + if (!_activeGraph->_autoScrolling + && _activeGraph->_playButton->containsPoint(event->x, event->y)) { - _autoScaling = true; - _autoScrolling = true; + _activeGraph->_autoScaling = true; + _activeGraph->_autoScrolling = true; queue_draw(); } else { _trackingDrag = true; - _autoScaling = false; - _autoScrolling = false; + _activeGraph->_autoScaling = false; + _activeGraph->_autoScrolling = false; _dragOriginX = event->x; _dragOriginY = event->y; - _dragOrigLeft = _left; - _dragOrigRight = _right; + _dragOrigLeft = _activeGraph->_left; + _dragOrigRight = _activeGraph->_right; } return true; } @@ -339,14 +142,14 @@ namespace systemtap x = event->x; y = event->y; } - if (_trackingDrag) + if (_trackingDrag && _activeGraph) { Gtk::Allocation allocation = get_allocation(); const int width = allocation.get_width(); double motion = (x - _dragOriginX) / (double) width; double increment = motion * (_dragOrigLeft - _dragOrigRight); - _left = _dragOrigLeft + increment; - _right = _dragOrigRight + increment; + _activeGraph->_left = _dragOrigLeft + increment; + _activeGraph->_right = _dragOrigRight + increment; queue_draw(); } return true; @@ -354,11 +157,20 @@ namespace systemtap bool GraphWidget::on_scroll_event(GdkEventScroll* event) { - if (event->direction == GDK_SCROLL_UP) - _zoomFactor += .1; - else if (event->direction == GDK_SCROLL_DOWN) - _zoomFactor -= .1; - queue_draw(); + for (GraphList::iterator gitr = _graphs.begin(); + gitr != _graphs.end(); + ++gitr) + { + if ((*gitr)->containsPoint(event->x, event->y)) + { + if (event->direction == GDK_SCROLL_UP) + (*gitr)->_zoomFactor += .1; + else if (event->direction == GDK_SCROLL_DOWN) + (*gitr)->_zoomFactor -= .1; + queue_draw(); + break; + } + } return true; } |