----- Forwarded Message -----
From: "Olivier Tarnus" <o.tarnus@xxxxxxx>
To: "Nathan Scott" <nscott@xxxxxxxxxx>
Sent: Friday, March 6, 2009 11:51:22 AM GMT +10:00 Canberra / Melbourne / Sydney
Subject: pmchart trackers
Hi Nathan
Here is a little patch, tell me what you think about the feature...
Bye
Olivier
diff --git a/src/chart/chart.cpp b/src/chart/chart.cpp
index e3bafad..78140e6 100644
--- a/src/chart/chart.cpp
+++ b/src/chart/chart.cpp
@@ -75,6 +75,9 @@ Chart::Chart(GroupControl *group) : Gadget(group)
my.sequence = 0;
my.yMin = -1;
my.yMax = -1;
+ my.row=0;
+ my.vmarkers = false;
+ my.tmarker = false;
my.picker = new QwtPlotPicker(QwtPlot::xBottom, QwtPlot::yLeft,
QwtPicker::PointSelection | QwtPicker::DragSelection,
QwtPlotPicker::CrossRubberBand, QwtPicker::AlwaysOff,
@@ -86,8 +89,21 @@ Chart::Chart(GroupControl *group) : Gadget(group)
SLOT(selected(const QwtDoublePoint &)));
connect(my.picker, SIGNAL(moved(const QwtDoublePoint &)),
SLOT(moved(const QwtDoublePoint &)));
-
setWidget(my.chart);
+
+ QPen *markerPen = new QPen(QColor(Qt::white));
+ markerPen->setStyle(Qt::DotLine);
+ my.timeMarker = new QwtPlotMarker();
+ my.timeMarker->setLineStyle(QwtPlotMarker::VLine);
+ my.timeMarker->setLinePen(*markerPen);
+ my.timeMarker->setSymbol( QwtSymbol( QwtSymbol::DTriangle,
QBrush(Qt::white), QPen(Qt::white), QSize(7,7) ) );
+ my.timeMarker->setXValue( 0.0 );
+ my.timeMarker->setZ( 100000.0 ); // Arbitrary,
should be above all others
+ my.timeMarker->hide();
+ my.timeMarker->attach(my.chart);
+ setTMarker(true);
+ my.chart->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(my.chart,SIGNAL(customContextMenuRequested(const QPoint &
)),this,SLOT(popUpMenu(const QPoint &)));
replot();
}
@@ -101,8 +117,14 @@ Chart::~Chart()
free(plot->data);
if (plot->plotData != NULL)
free(plot->plotData);
+ if (plot->valueMarker!= NULL)
+ free(plot->valueMarker);
free(plot);
}
+ if (my.timeMarker !=NULL) {
+ free(my.timeMarker);
+ }
+
}
void Chart::topLevelChanged(bool topLevel)
@@ -278,7 +300,6 @@ void Chart::updateValues(bool forward, bool visible)
}
}
}
-
#if DESPERATE
for (m = 0; m < my.plots.size(); m++)
console->post(PmChart::DebugForce, "metric[%d] value %f plot %f", m,
@@ -457,10 +478,12 @@ void Chart::replot()
console->post("Chart::replot vh=%d, %d plots)", vh, my.plots.size());
#endif
- for (int m = 0; m < my.plots.size(); m++)
+ for (int m = 0; m < my.plots.size(); m++) {
my.plots[m]->curve->setRawData(group()->timeAxisData(),
my.plots[m]->plotData,
qMin(vh, my.plots[m]->dataCount));
+ if (my.plots[m]->vmarker) my.plots[m]->valueMarker->setXValue(
my.chart->axisScaleDiv(QwtPlot::xBottom)->lBound() ); // reposition the
value marker at left
+ }
my.chart->replot();
}
@@ -606,12 +629,16 @@ int Chart::addPlot(pmMetricSpec *pmsp, const char *legend)
// force plot to be visible, legend visibility is controlled by
// legend() to a state matching the initial state
- showCurve(plot->curve, true);
plot->removed = false;
plot->hidden = false;
+
+ // Create the valueMarker
+ plot->valueMarker = new QwtPlotMarker(); // Add a value marker for each
plot
+ plot->valueMarker ->attach(my.chart);
// set the prevailing chart style and the default color
- setStroke(plot, my.style, nextColor(scheme(), &my.sequence));
+ plot->color = nextColor(scheme(), &my.sequence);
+ setStroke(plot, my.style, plot->color);
maxCount = 0;
for (int m = 0; m < my.plots.size(); m++)
@@ -635,6 +662,29 @@ int Chart::addPlot(pmMetricSpec *pmsp, const char *legend)
plot->scale = 0.001;
}
+ plot->vmarker = true;
+ plot->valueMarker ->setLineStyle(QwtPlotMarker::HLine);
+
+//plot->valueMarker ->setSymbol( QwtSymbol(QwtSymbol::XCross,
+ // plot->curve->brush(), QPen(plot->curve->pen()), QSize(10,10)) );
+ //plot->valueMarker ->setLinePen(QPen(plot->color));
+ //plot->valueMarker ->setLinePen(QPen(nextColor(my.scheme, &my.sequence)));
+ plot->valueMarker ->setXValue( 0.0 );
+ plot->valueMarker ->setZ( 1001 ); // Arbitrary,
should be above all others plotItems
+ QwtText text("bla");
+ text.setFont(globalFont);
+ //text.setColor(QColor(plot->curve->brush().color()));
+ //text.setColor(plot->color);
+ text.setBackgroundPen(QPen(Qt::black));
+ text.setBackgroundBrush(QColor(Qt::black));
+ plot->valueMarker->setLabel(text);
+ plot->valueMarker->setLabelAlignment(Qt::AlignRight | Qt::AlignBottom);
+ plot->valueMarker ->setSymbol( QwtSymbol(QwtSymbol::RTriangle,
+ plot->curve->brush(), QPen(plot->curve->pen()), QSize(7,7)) );
+ plot->valueMarker->hide();
+
+ showCurve(plot->curve, true);
+
return my.plots.size() - 1;
}
@@ -645,6 +695,7 @@ void Chart::revivePlot(int m)
if (my.plots[m]->removed) {
my.plots[m]->removed = false;
my.plots[m]->curve->attach(my.chart);
+ my.plots[m]->valueMarker->attach(my.chart);
}
}
@@ -654,6 +705,7 @@ void Chart::delPlot(int m)
my.plots[m]->removed = true;
my.plots[m]->curve->detach();
+ my.plots[m]->valueMarker->detach();
// We can't really do this properly (free memory, etc) - working around
// metrics class limit (its using an ordinal index for metrics, remove any
@@ -864,6 +916,19 @@ void Chart::setStroke(Plot *plot, Style style, QColor
color)
redoPlotData();
replot();
}
+
+ QPen *vmPen = new QPen(color);
+ vmPen->setStyle(Qt::DotLine);
+ plot->valueMarker->setLinePen(*vmPen);
+ QwtSymbol vmarksymbol= plot->valueMarker->symbol();
+ vmarksymbol.setPen(plot->curve->pen());
+ vmarksymbol.setBrush(QBrush(color, Qt::SolidPattern));
+ plot->valueMarker->setSymbol(vmarksymbol);
+ //vmarksymbol.setStyle(plot->curve->style());
+ plot->valueMarker->label().setColor(color);
+ plot->valueMarker->label().setBackgroundPen(QPen(Qt::black));
+ plot->valueMarker->label().setBackgroundBrush(QBrush(Qt::black,
Qt::SolidPattern));
+
}
void Chart::redoPlotData(void)
@@ -998,6 +1063,9 @@ void Chart::selected(const QwtDoublePoint &p)
string.sprintf("[%.2f %s at %s]",
(float)p.y(), pmUnitsStr(&my.units), timeHiResString(p.x()));
pmchart->setValueText(string);
+ group()->showTimeMarkers(group()->timeMarkers());
+ group()->showSelectedChartsVMarkers(true);
+ group()->setAllChartMarkersX(p.x());
}
void Chart::moved(const QwtDoublePoint &p)
@@ -1007,6 +1075,7 @@ void Chart::moved(const QwtDoublePoint &p)
string.sprintf("[%.2f %s at %s]",
(float)p.y(), pmUnitsStr(&my.units), timeHiResString(p.x()));
pmchart->setValueText(string);
+ group()->setAllChartMarkersX(p.x());
}
bool Chart::legendVisible()
@@ -1299,3 +1368,124 @@ void Chart::resizeEvent(QResizeEvent *e)
if (e->size().width() != e->oldSize().width())
resetLocalTimeAxis();
}
+
+/*void Chart::setRow(int row=0)
+{
+ my.row=row;
+}*/
+void Chart::toggleTMarker(void)
+{
+ setTMarker(!my.tmarker);
+}
+
+void Chart::setTMarker(bool state = true)
+{
+ my.tmarker = state;
+ showTMarker(state);
+}
+
+void Chart::showTMarker(bool state = true)
+{
+ if (state && my.tmarker) my.timeMarker->show();
+ else my.timeMarker->hide();
+ my.chart->replot();
+}
+
+
+void Chart::setVMarker(int m=0, bool state = true)
+{
+ my.plots[m]->vmarker = state;
+}
+
+void Chart::showVMarker(int m=0, bool state = true)
+{
+ if (state && my.plots[m]->vmarker) my.plots[m]->valueMarker->show();
+ else my.plots[m]->valueMarker->hide();
+}
+
+void Chart::setVMarkers(bool state = true)
+{
+ my.vmarkers = state;
+ showVMarkers(state);
+}
+
+void Chart::showVMarkers(bool state = true)
+{
+ for (int m = 0; m < my.plots.size(); m++)
+ if (my.plots[m]->vmarker && my.plots[m]->curve->isVisible())
+ {
+ showVMarker(m,state);
+ }
+ my.chart->replot();
+}
+
+
+void Chart::setMarkersXValue(double x)
+{
+ int point = 0;
+ int n;
+ double *xdatas = group()->timeAxisData();
+
+ if (my.tmarker && group()->timeMarkers() ) {
+
my.timeMarker->setValue(x,my.chart->axisScaleDiv(QwtPlot::yLeft)->hBound() -
((my.chart->axisScaleDiv(QwtPlot::yLeft)->hBound()-my.chart->axisScaleDiv(QwtPlot::yLeft)->lBound())/50));
// position the time marker to x value
+
+ if (my.vmarkers || group()->allVMarkers()) {
+ for (n = group()->samples()-1; n >= 0 ; n--) // find nearest
index before our x value
+ if ( x > xdatas[n]){
+ point = n;
+ }
+ for (int m = 0; m < my.plots.size(); m++) {
+ if (my.plots[m]->vmarker && my.plots[m]->curve->isVisible()) {
+ my.plots[m]->valueMarker->setValue(
my.chart->axisScaleDiv(QwtPlot::xBottom)->lBound(),
my.plots[m]->plotData[point]); // and position the value marker
+ QString string;
+ string.sprintf("%.2f %s", my.plots[m]->plotData[point],
pmUnitsStr(&my.units));
+ QwtText mylabel = my.plots[m]->valueMarker->label();
+ mylabel.setColor(my.plots[m]->color);
+ mylabel.setText(string);
+ my.plots[m]->valueMarker->setLabel(mylabel);
+ }
+
+ }
+ }
+ }
+ my.chart->replot();
+}
+
+void Chart::popUpMenu(const QPoint &pos)
+{
+ qDebug()<<"chart context menu ?"<<pos;
+ QMenu menu;
+ QAction * EditProperties= new QAction(tr("Edit"), this);
+ connect(EditProperties, SIGNAL(triggered()), this, SLOT(openEditBox()) );
+ menu.addAction(EditProperties);
+ QAction * SetTimemarker ;
+ if (my.tmarker) SetTimemarker = menu.addAction( QIcon("toggled.png"),
tr("Toggle TimeMarker") );
+ else SetTimemarker = menu.addAction( QIcon("untoggled.png"), tr("Toggle
TimeMarker") );
+ connect(SetTimemarker, SIGNAL(triggered()), this, SLOT(toggleTMarker()) );
+ QMenu * vmarkersMenu = menu.addMenu("Toggle ValueMarkers");
+ for (int m = 0; m < my.plots.size(); m++) {
+ Plot *plot = my.plots[m];
+ if (plot->valueMarker!= NULL) {
+ QAction * VMarkerAction ;
+ if (plot->vmarker) VMarkerAction =
vmarkersMenu->addAction(QIcon("toggled.png"),tr(plot->legend));
+ else VMarkerAction =
vmarkersMenu->addAction(QIcon("untoggled.png"),tr(plot->legend));
+ VMarkerAction->setData(QVariant(m));
+ connect(VMarkerAction, SIGNAL(triggered()), this,
SLOT(menuToggleVMarker()) );
+ }
+ }
+ menu.popup(pos);
+ menu.exec(QCursor::pos());
+}
+
+void Chart::openEditBox(void)
+{
+ pmchart->editChart(this);
+}
+
+void Chart::menuToggleVMarker(void)
+{
+ QAction *action = qobject_cast<QAction *>(sender());
+
setVMarker(action->data().toInt(),!my.plots[action->data().toInt()]->vmarker);
+ showVMarker(action->data().toInt());
+}
+
diff --git a/src/chart/chart.h b/src/chart/chart.h
index f06dea9..51db82e 100644
--- a/src/chart/chart.h
+++ b/src/chart/chart.h
@@ -15,6 +15,10 @@
#ifndef CHART_H
#define CHART_H
+//
+// Chart class ... multiple plots per chart, multiple charts per tab
+//
+
#include <QtCore/QString>
#include <QtCore/QDateTime>
#include <QtGui/QColor>
@@ -22,6 +26,8 @@
#include <qwt_plot.h>
#include <qwt_plot_curve.h>
#include <qwt_plot_picker.h>
+#include <qwt_plot_marker.h>
+#include <qwt_symbol.h>
#include <qwt_double_rect.h>
#include <qmc_metric.h>
#include "gadget.h"
@@ -107,6 +113,13 @@ public:
bool, QColor&, QString&);
static QColor schemeColor(QString, int *);
+ void setTMarker(bool);
+ void showTMarker(bool);
+ void setVMarkers(bool);
+ void showVMarkers(bool);
+ void setMarkersXValue(double);
+ void setVMarker(int, bool);
+ void showVMarker(int,bool);
private slots:
void selected(const QwtDoublePoint &);
@@ -114,6 +127,10 @@ private slots:
void showCurve(QwtPlotItem *, bool);
void resizeEvent(QResizeEvent *);
void topLevelChanged(bool);
+ void popUpMenu(const QPoint &pos);
+ void openEditBox(void);
+ void toggleTMarker(void);
+ void menuToggleVMarker(void);
private:
typedef struct {
@@ -130,6 +147,8 @@ private:
bool removed;
bool hidden; // true if hidden through legend push button
pmUnits units;
+ bool vmarker; // Use a value marker for this plot?
+ QwtPlotMarker *valueMarker;
} Plot;
bool isStepped(Plot *plot);
@@ -159,7 +178,11 @@ private:
double yMin;
double yMax;
QwtPlotPicker *picker;
+ QwtPlotMarker *timeMarker;
pmUnits units;
+ bool vmarkers; // use value markers in this graph?
+ bool tmarker; // use value markers in this graph?
+ int row;
} my;
};
diff --git a/src/chart/gadget.cpp b/src/chart/gadget.cpp
index 7f6bfaf..65a7950 100644
--- a/src/chart/gadget.cpp
+++ b/src/chart/gadget.cpp
@@ -265,3 +265,37 @@ void Gadget::topLevelChanged(bool top)
else
pmchart->activeView()->addGadget(this);
}
+
+
+void Gadget::setTMarker(bool state = true)
+{
+ my.tmarker = state;
+}
+
+
+void Gadget::setVMarkers(bool state = true)
+{
+ my.vmarkers = state;
+}
+
+void Gadget::showTMarker(bool state = true)
+{
+}
+
+void Gadget::showVMarkers(bool state = true)
+{
+}
+
+bool Gadget::tMarker()
+{
+ return my.tmarker;
+}
+
+bool Gadget::vMarkers()
+{
+ return my.vmarkers;
+}
+
+void Gadget::setMarkersXValue(double x)
+{
+}
diff --git a/src/chart/gadget.h b/src/chart/gadget.h
index 7948d15..bf70266 100644
--- a/src/chart/gadget.h
+++ b/src/chart/gadget.h
@@ -71,6 +71,15 @@ public:
virtual QString pmloggerSyntax(); // pmlogger config text for all metrics
virtual QString pmloggerMetricSyntax(int); // config text for 1 metric
+ virtual void setTMarker(bool);
+ virtual void showTMarker(bool);
+ virtual void setVMarkers(bool);
+ virtual void showVMarkers(bool);
+ virtual void setMarkersXValue(double);
+ virtual bool tMarker();
+ virtual bool vMarkers();
+
+
signals:
void currentChanged(bool);
void schemeChanged(const QString &);
@@ -83,6 +92,9 @@ private:
GroupControl *group;
QString scheme;
bool current;
+ bool vmarkers; // use value markers in this graph?
+ bool tmarker; // use value markers in this graph?
+
} my;
};
diff --git a/src/chart/groupcontrol.cpp b/src/chart/groupcontrol.cpp
index 4e8c2ca..fcb591b 100644
--- a/src/chart/groupcontrol.cpp
+++ b/src/chart/groupcontrol.cpp
@@ -53,6 +53,12 @@ void GroupControl::init(int samples, int visible,
my.timeData = (double *)malloc(samples * sizeof(double));
for (int i = 0; i < samples; i++)
my.timeData[i] = my.realPosition - (i * my.realDelta);
+ my.markersTimer = new QTimer(this);
+ my.markersTimer ->setSingleShot(true);
+ connect(my.markersTimer, SIGNAL(timeout()), this, SLOT(markersTimeout()));
+ resetMarkersTimer();
+ my.timeMarkers=1;
+ my.allVMarkers=1;
}
bool GroupControl::isArchiveSource(void)
@@ -609,3 +615,77 @@ void GroupControl::newButtonState(PmTime::State s,
PmTime::Mode m, bool record)
else
my.buttonState = TimeButton::StoppedArchive;
}
+
+
+// Markers
+
+void GroupControl::showTimeMarkers(bool state)
+{
+ for (int i = 0; i < gadgetCount() ; i++)
+ my.gadgetsList.at(i)->showTMarker(state);
+ // pmchart->showTimeAxisMarker(state);
+}
+
+void GroupControl::enableChartVMarkers(int chart=0, bool state=true)
+{
+ my.gadgetsList.at(chart)->setVMarkers(state);
+ resetMarkersTimer();
+}
+
+void GroupControl::enableAllChartsVMarkers(bool state = true)
+{
+ my.allVMarkers = state;
+ showTimeMarkers(state);
+ showSelectedChartsVMarkers(state);
+ resetMarkersTimer();
+}
+
+void GroupControl::showSelectedChartsVMarkers(bool state = true)
+{
+ for (int i = 0; i < gadgetCount() ; i++){
+ if (my.allVMarkers) my.gadgetsList.at(i)->showVMarkers(state);
+ else my.gadgetsList.at(i)->showVMarkers(state &&
my.gadgetsList.at(i)->vMarkers());
+ }
+}
+
+void GroupControl::setAllChartMarkersX(double x)
+{
+ for (int i = 0; i < gadgetCount() ; i++) {
+ my.gadgetsList.at(i)->setMarkersXValue(x);
+ //pmchart->setTimeAxisMarkerXValue(x);
+ }
+ resetMarkersTimer();
+}
+
+void GroupControl::markersTimeout()
+{
+ showTimeMarkers(false);
+ showSelectedChartsVMarkers(false);
+ if (my.allVMarkers)
+ for (int i = 0; i < gadgetCount(); i++)
+ my.gadgetsList.at(i)->showVMarkers(false);
+ console->post("GroupControl::timeout()");
+}
+
+void GroupControl::resetMarkersTimer()
+{
+ console->post("GroupControl::resetMarkersTimer()");
+ if (my.markersTimer->isActive())
+ my.markersTimer->stop();
+ my.markersTimer->start(GroupControl::defaultMarkersTimerTimeout());
+}
+
+int GroupControl::samples(void)
+{
+ return my.samples;
+}
+
+bool GroupControl::allVMarkers()
+{
+ return my.allVMarkers;
+}
+
+bool GroupControl::timeMarkers()
+{
+ return my.timeMarkers;
+}
diff --git a/src/chart/groupcontrol.h b/src/chart/groupcontrol.h
index 43e568b..4f2de5d 100644
--- a/src/chart/groupcontrol.h
+++ b/src/chart/groupcontrol.h
@@ -19,6 +19,8 @@
#include <QtGui/QLabel>
#include <QtGui/QLayout>
#include <QtGui/QPixmap>
+#include <QtGui/QSplitter>
+#include <QTimer>
#include <qwt_plot.h>
#include <qwt_scale_draw.h>
#include <qmc_group.h>
@@ -62,6 +64,22 @@ public:
TimeButton::State buttonState();
PmTime::State pmtimeState();
void newButtonState(PmTime::State, PmTime::Mode, bool);
+
+ int samples(void);
+ void showTimeMarkers(bool);
+ void enableChartVMarkers(bool);
+ void enableChartVMarkers(int,bool);
+ void enableAllChartsVMarkers(bool);
+ void showSelectedChartsVMarkers(bool);
+ bool allVMarkers();
+ bool timeMarkers();
+ void setAllChartMarkersX(double); // modify position of markers in
all charts
+ void resetMarkersTimer();
+ static int defaultMarkersTimerTimeout() { return 5000; } // milliseconds
+
+public slots:
+ virtual void markersTimeout();
+
private:
typedef enum {
@@ -98,6 +116,12 @@ private:
PmTime::Source pmtimeSource; // reliable archive/host test
PmTime::State pmtimeState;
State timeState;
+
+ QSplitter * vsplitter; // dynamically divides Tab by rows
vertically
+ QSplitter ** hsplitters; // dynamically divide each row
+ QTimer *markersTimer; // hide chart markers at timeout
+ bool timeMarkers;
+ bool allVMarkers;
} my;
};
diff --git a/src/chart/pmchart.cpp b/src/chart/pmchart.cpp
index 559d28e..fd6de99 100644
--- a/src/chart/pmchart.cpp
+++ b/src/chart/pmchart.cpp
@@ -578,22 +578,29 @@ void PmChart::fileNewChart()
void PmChart::editChart()
{
+ Chart *cp = (Chart *)activeGadget();
+ editChart(cp);
+}
+
+void PmChart::editChart( Chart *cp)
+{
bool yAutoScale;
double yMin, yMax;
- Chart *cp = (Chart *)activeGadget();
- setupDialogs();
- my.editchart->reset(cp, cp->style() - 1, cp->scheme());
- my.editchart->titleLineEdit->setText(cp->title());
- my.editchart->legendOn->setChecked(cp->legendVisible());
- my.editchart->legendOff->setChecked(!cp->legendVisible());
- my.editchart->antiAliasingOn->setChecked(cp->antiAliasing());
- my.editchart->antiAliasingOff->setChecked(!cp->antiAliasing());
- my.editchart->antiAliasingAuto->setChecked(false);
- cp->scale(&yAutoScale, &yMin, &yMax);
- my.editchart->setScale(yAutoScale, yMin, yMax);
- my.editchart->setScheme(cp->scheme(), cp->sequence());
- my.editchart->show();
+ if (cp != NULL) {
+ setupDialogs();
+ my.editchart->reset(cp, cp->style() - 1, cp->scheme());
+ my.editchart->titleLineEdit->setText(cp->title());
+ my.editchart->legendOn->setChecked(cp->legendVisible());
+ my.editchart->legendOff->setChecked(!cp->legendVisible());
+ my.editchart->antiAliasingOn->setChecked(cp->antiAliasing());
+ my.editchart->antiAliasingOff->setChecked(!cp->antiAliasing());
+ my.editchart->antiAliasingAuto->setChecked(false);
+ cp->scale(&yAutoScale, &yMin, &yMax);
+ my.editchart->setScale(yAutoScale, yMin, yMax);
+ my.editchart->setScheme(cp->scheme(), cp->sequence());
+ my.editchart->show();
+ }
}
void PmChart::acceptEditChart()
diff --git a/src/chart/pmchart.h b/src/chart/pmchart.h
index 649d08e..4b8a22c 100644
--- a/src/chart/pmchart.h
+++ b/src/chart/pmchart.h
@@ -16,6 +16,7 @@
#include "ui_pmchart.h"
#include "statusbar.h"
+#include "chart.h"
#include <pmtime.h>
class Gadget;
@@ -135,6 +136,7 @@ public slots:
virtual void acceptNewChart();
virtual void fileNewChart();
virtual void editChart();
+ virtual void editChart(Chart *);
virtual void acceptEditChart();
virtual void closeChart();
virtual void editView();
--
Nathan
|