summaryrefslogtreecommitdiffstats
path: root/grapher/GraphWidget.cxx
diff options
context:
space:
mode:
authorTim Moore <timoore@redhat.com>2009-07-27 12:46:30 +0200
committerTim Moore <timoore@redhat.com>2009-07-28 11:21:15 +0200
commit364ad890e341bb60ae169af69933a382d4bf9f81 (patch)
tree4b2fb5eb5644bdebc38b935077fa96ace8d831c5 /grapher/GraphWidget.cxx
parenta030ced8c0b8109ba7b23bbbc65deddf88154a2f (diff)
downloadsystemtap-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.cxx294
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;
}