diff --git a/plugins/pyqcustomplot/CMakeLists.txt b/plugins/pyqcustomplot/CMakeLists.txt index 8e7fe9cccef2e836a90443e52ffd4b045126e378..a751a24b5d3891b12cb6b5795133f7619f8912fc 100644 --- a/plugins/pyqcustomplot/CMakeLists.txt +++ b/plugins/pyqcustomplot/CMakeLists.txt @@ -32,6 +32,8 @@ GEPETTO_GUI_PLUGIN(pyqcustomplot qcustomplot.h plugin.hh decorator.hh + wrapper/qcp.hh + qcpitemrichtext.hh SOURCES qcustomplot.cpp diff --git a/plugins/pyqcustomplot/decorator.cc b/plugins/pyqcustomplot/decorator.cc index e3d5cd7e9aa7342b6359e1612015ddfbe7991550..29643394a3b193fb1ba35d2c400506d8fcbcc7b9 100644 --- a/plugins/pyqcustomplot/decorator.cc +++ b/plugins/pyqcustomplot/decorator.cc @@ -15,16 +15,51 @@ // gepetto-viewer-corba. If not, see <http://www.gnu.org/licenses/>. #include <decorator.hh> +#include <wrapper/qcp.hh> #include <PythonQt.h> void registerQCustomPlot () { + PythonQt::self()->registerCPPClass ("QCP", "", "QCustomPlot", PythonQtCreateObject<wrapper::PyQCP>, NULL); + + PythonQt::self()->registerClass (&QCustomPlot ::staticMetaObject , "QCustomPlot"); + PythonQt::self()->registerClass (&QCPPainter ::staticMetaObject , "QCustomPlot"); + PythonQt::self()->registerClass (&QCPLayer ::staticMetaObject , "QCustomPlot"); + + PythonQt::self()->registerClass (&QCPLayerable ::staticMetaObject, "QCustomPlot"); + + PythonQt::self()->registerClass (&QCPAbstractPlottable::staticMetaObject, "QCustomPlot"); + PythonQt::self()->registerClass (&QCPBars ::staticMetaObject, "QCustomPlot"); + PythonQt::self()->registerClass (&QCPColorMap ::staticMetaObject, "QCustomPlot"); + PythonQt::self()->registerClass (&QCPCurve ::staticMetaObject, "QCustomPlot"); + PythonQt::self()->registerClass (&QCPFinancial ::staticMetaObject, "QCustomPlot"); + PythonQt::self()->registerClass (&QCPGraph ::staticMetaObject, "QCustomPlot"); + + PythonQt::self()->registerClass (&QCPAbstractItem ::staticMetaObject, "QCustomPlot"); + PythonQt::self()->registerClass (&QCPItemBracket ::staticMetaObject , "QCustomPlot"); + PythonQt::self()->registerClass (&QCPItemCurve ::staticMetaObject , "QCustomPlot"); + PythonQt::self()->registerClass (&QCPItemEllipse ::staticMetaObject , "QCustomPlot"); + PythonQt::self()->registerClass (&QCPItemLine ::staticMetaObject , "QCustomPlot"); + PythonQt::self()->registerClass (&QCPItemPixmap ::staticMetaObject , "QCustomPlot"); + PythonQt::self()->registerClass (&QCPItemRect ::staticMetaObject , "QCustomPlot"); + PythonQt::self()->registerClass (&QCPItemStraightLine::staticMetaObject , "QCustomPlot"); + PythonQt::self()->registerClass (&QCPItemText ::staticMetaObject , "QCustomPlot"); + PythonQt::self()->registerClass (&QCPItemRichText ::staticMetaObject, "QCustomPlot"); + PythonQt::self()->registerClass (&QCPItemTracer ::staticMetaObject , "QCustomPlot"); + //PythonQt::self()->addParentClass ("QCPItemRichText", "QCPItemText", PythonQtUpcastingOffset<QCPItemRichText,QCPItemText>()); + + PythonQt::self()->registerClass (&QCPLayoutElement::staticMetaObject, "QCustomPlot"); + PythonQt::self()->registerClass (&QCPLayout ::staticMetaObject, "QCustomPlot"); + PythonQt::self()->registerClass (&QCPAxisRect ::staticMetaObject, "QCustomPlot"); + PythonQt::self()->registerClass (&QCPLayoutGrid ::staticMetaObject, "QCustomPlot"); + PythonQt::self()->registerClass (&QCPLegend ::staticMetaObject, "QCustomPlot"); + PythonQt::self()->registerClass (&QCPAxis ::staticMetaObject, "QCustomPlot"); + PythonQt::self()->addDecorators (new QCustomPlotDecorator ()); PythonQt::self()->registerCPPClass ("QCPPainter" , "QPainter", "QCustomPlot"); PythonQt::self()->registerCPPClass ("QCustomPlot" , "QWidget" , "QCustomPlot"); // PythonQt::self()->registerCPPClass ("QCPAxisPainterPrivate", "QGraphicsItem" , "QCustomPlot"); - // PythonQt::self()->registerCPPClass ("QCPItemPosition" , "QGraphicsItem" , "QCustomPlot"); PythonQt::self()->registerCPPClass ("QCPLayer" , "QObject" , "QCustomPlot"); // PythonQt::self()->registerCPPClass ("QCPPlotTitle" , "QGraphicsItem" , "QCustomPlot"); // PythonQt::self()->registerCPPClass ("QCPAbstractLegendItem", "QGraphicsItem" , "QCustomPlot"); @@ -32,11 +67,24 @@ void registerQCustomPlot () // PythonQt::self()->registerCPPClass ("QCPColorScale" , "QGraphicsItem" , "QCustomPlot"); // PythonQt::self()->registerCPPClass ("QCPBars" , "QGraphicsItem" , "QCustomPlot"); + PythonQt::self()->registerCPPClass ("QCPItemAnchor" , NULL , "QCustomPlot"); + PythonQt::self()->registerCPPClass ("QCPItemPosition" , "QCPItemAnchor" , "QCustomPlot"); + // Children of QCPLayerable PythonQt::self()->registerCPPClass ("QCPLayerable" , "QObject" , "QCustomPlot"); PythonQt::self()->registerCPPClass ("QCPAbstractItem" , "QCPLayerable" , "QCustomPlot"); + PythonQt::self()->registerCPPClass ("QCPItemBracket" , "QCPAbstractItem" , "QCustomPlot"); + PythonQt::self()->registerCPPClass ("QCPItemCurve" , "QCPAbstractItem" , "QCustomPlot"); PythonQt::self()->registerCPPClass ("QCPItemEllipse" , "QCPAbstractItem" , "QCustomPlot"); + PythonQt::self()->registerCPPClass ("QCPItemLine" , "QCPAbstractItem" , "QCustomPlot"); + PythonQt::self()->registerCPPClass ("QCPItemPixmap" , "QCPAbstractItem" , "QCustomPlot"); + PythonQt::self()->registerCPPClass ("QCPItemRect" , "QCPAbstractItem" , "QCustomPlot"); + PythonQt::self()->registerCPPClass ("QCPItemStraightLine" , "QCPAbstractItem" , "QCustomPlot"); + PythonQt::self()->registerCPPClass ("QCPItemText" , "QCPAbstractItem" , "QCustomPlot"); + PythonQt::self()->registerCPPClass ("QCPItemTracer" , "QCPAbstractItem" , "QCustomPlot"); + + PythonQt::self()->registerCPPClass ("QCPItemRichText" , "QCPItemText" , "QCustomPlot"); PythonQt::self()->registerCPPClass ("QCPAbstractPlottable" , "QCPLayerable" , "QCustomPlot"); PythonQt::self()->registerCPPClass ("QCPBars" , "QCPAbstractPlottable" , "QCustomPlot"); diff --git a/plugins/pyqcustomplot/decorator.hh b/plugins/pyqcustomplot/decorator.hh index 8f5b3cb507bcdc62e6483c27b55fe5b4c5296691..cb8dadb767bea473e7d0ce4facd96960827cedb6 100644 --- a/plugins/pyqcustomplot/decorator.hh +++ b/plugins/pyqcustomplot/decorator.hh @@ -1,4 +1,5 @@ #include <qcustomplot.h> +#include <qcpitemrichtext.hh> #include <QObject> @@ -36,32 +37,37 @@ class QCustomPlotDecorator : public QObject { return o->graph(graphnum); } - void replot (QCustomPlot* o) //replot object to visualise new data + void rescaleAxes(QCustomPlot* o, bool v = true) //rescale axis automatically if data does not fit { - o->replot(); + o->rescaleAxes(v); } - void show (QCustomPlot* o) //open new window with graph + /// \param interaction See QCP::Interaction + void setInteraction(QCustomPlot* o, int interaction, bool enabled = true) { - o->show(); + o->setInteraction((QCP::Interaction)interaction, enabled); } - void setWindowTitle(QCustomPlot* o,QString title) //set title of window of graph + + bool savePdf (QCustomPlot* o, const QString &fileName, bool noCosmeticPen=false, int width=0, int height=0, const QString &pdfCreator=QString(), const QString &pdfTitle=QString()) { - o->setWindowTitle(title); + return o->savePdf (fileName, noCosmeticPen, width, height, pdfCreator, pdfTitle); } - void rescaleAxes(QCustomPlot* o, bool v = true) //rescale axis automatically if data does not fit + bool savePng (QCustomPlot* o, const QString &fileName, int width=0, int height=0, double scale=1.0, int quality=-1) { - o->rescaleAxes(v); + return o->savePng (fileName, width, height, scale, quality); } - QCPLayoutGrid* plotLayout (QCustomPlot* o) { return o->plotLayout (); } - void setAutoAddPlottableToLegend (QCustomPlot* o, bool v) + bool saveJpg (QCustomPlot* o, const QString &fileName, int width=0, int height=0, double scale=1.0, int quality=-1) { - o->setAutoAddPlottableToLegend (v); + return o->saveJpg (fileName, width, height, scale, quality); } - /// \param interaction See QCP::Interaction - void setInteraction(QCustomPlot* o, int interaction, bool enabled = true) + bool saveBmp (QCustomPlot* o, const QString &fileName, int width=0, int height=0, double scale=1.0) { - o->setInteraction((QCP::Interaction)interaction, enabled); + return o->saveBmp (fileName, width, height, scale); + } + bool saveRastered (QCustomPlot* o, const QString &fileName, int width, int height, double scale, const char *format, int quality=-1) + { + return o->saveRastered (fileName, width, height, scale, format, quality); } + QCPAxis* xAxis (QCustomPlot* o) { return o->xAxis ; } QCPAxis* xAxis2 (QCustomPlot* o) { return o->xAxis2; } QCPAxis* yAxis (QCustomPlot* o) { return o->yAxis ; } @@ -71,6 +77,8 @@ class QCustomPlotDecorator : public QObject /// \} /// \name QCPAxis + /// \todo Most of this function should be removed as they duplicates the + /// QProperty methods. /// \{ int selectedParts(const QCPAxis* a) { @@ -169,22 +177,10 @@ class QCustomPlotDecorator : public QObject { ap->rescaleAxes(v); } - void setName (QCPAbstractPlottable* ap, const QString &n) - { - ap->setName(n); - } - void setPen (QCPAbstractPlottable* ap, const QPen &pen) - { - ap->setPen(pen); - } /// \} /// \name QCPLayerable /// \{ - void setVisible (QCPLayerable* l, const bool &v) - { - l->setVisible(v); - } /// \} /// \name QCPLayoutGrid @@ -210,4 +206,41 @@ class QCustomPlotDecorator : public QObject ar->setRangeZoomAxes (horizontal, vertical); } /// \} + + /// \name QCPItemPosition + /// \{ + void setType (QCPItemPosition* ip, int type) { return ip->setType((QCPItemPosition::PositionType)type); } + bool setParentAnchor (QCPItemPosition* ip, QCPItemAnchor* a) { return ip->setParentAnchor (a); } + void setCoords (QCPItemPosition* ip, double k, double v) { return ip->setCoords (k, v); } + /// \} + + /// \name QCPAbstractItem + /// \{ + QCPItemPosition* position (QCPAbstractItem* ai, QString p) { return ai->position(p); } + QCPItemAnchor * anchor (QCPAbstractItem* ai, QString a) { return ai->anchor (a); } + /// \} + + /// \name QCPItemTracer + /// \{ + QCPItemTracer* new_QCPItemTracer (QCustomPlot* parent) { return new QCPItemTracer (parent); } + void delete_QCPItemTracer (QCPItemTracer* it) { delete it; } + /// \} + + /// \name QCPItemRichText + /// \{ + QCPItemRichText* new_QCPItemRichText (QCustomPlot* parent) { return new QCPItemRichText (parent); } + void delete_QCPItemRichText (QCPItemRichText* it) { delete it; } + /// \} + + /// \name QCPItemText + /// \{ + QCPItemText* new_QCPItemText (QCustomPlot* parent) { return new QCPItemText (parent); } + void delete_QCPItemText (QCPItemText* it) { delete it; } + /// \} + + /// \name QCPItemEllipse + /// \{ + QCPItemEllipse* new_QCPItemEllipse (QCustomPlot* parent) { return new QCPItemEllipse (parent); } + void delete_QCPItemEllipse (QCPItemEllipse* it) { delete it; } + /// \} }; diff --git a/plugins/pyqcustomplot/qcpitemrichtext.hh b/plugins/pyqcustomplot/qcpitemrichtext.hh new file mode 100644 index 0000000000000000000000000000000000000000..eb28da6ac0600ecb089b3e85c1510b6d6f549961 --- /dev/null +++ b/plugins/pyqcustomplot/qcpitemrichtext.hh @@ -0,0 +1,56 @@ +#ifndef QCP_ITEM_RICH_TEXT +#define QCP_ITEM_RICH_TEXT +#include <qcustomplot.h> + +class QCP_LIB_DECL QCPItemRichText : public QCPItemText +{ Q_OBJECT + Q_PROPERTY(QString text READ text WRITE setText) +public: + QCPItemRichText(QCustomPlot *parentPlot) + : QCPItemText (parentPlot) {} + virtual ~QCPItemRichText() {} + + void setText(const QString &text) + { + QCPItemText::setText (text); + doc.setHtml(text); + } + +protected: + // reimplemented virtual methods: + virtual void draw(QCPPainter *painter) + { + QPointF pos(position->pixelPoint()); + QTransform transform = painter->transform(); + transform.translate(pos.x(), pos.y()); + if (!qFuzzyIsNull(mRotation)) + transform.rotate(mRotation); + painter->setFont(mainFont()); + QRect textRect = painter->fontMetrics().boundingRect(0, 0, 0, 0, Qt::TextDontClip|mTextAlignment, mText); + QRect textBoxRect = textRect.adjusted(-mPadding.left(), -mPadding.top(), mPadding.right(), mPadding.bottom()); + QPointF textPos = getTextDrawPoint(QPointF(0, 0), textBoxRect, mPositionAlignment); // 0, 0 because the transform does the translation + textRect.moveTopLeft(textPos.toPoint()+QPoint(mPadding.left(), mPadding.top())); + textBoxRect.moveTopLeft(textPos.toPoint()); + qreal clipPadF = mainPen().widthF(); + int clipPad = (int)clipPadF; + QRect boundingRect = textBoxRect.adjusted(-clipPad, -clipPad, clipPad, clipPad); + if (transform.mapRect(boundingRect).intersects(painter->transform().mapRect(clipRect()))) + { + painter->setTransform(transform); + if ((mainBrush().style() != Qt::NoBrush && mainBrush().color().alpha() != 0) || + (mainPen().style() != Qt::NoPen && mainPen().color().alpha() != 0)) + { + painter->setPen(mainPen()); + painter->setBrush(mainBrush()); + painter->drawRect(textBoxRect); + } + painter->setBrush(Qt::NoBrush); + painter->setPen(QPen(mainColor())); + doc.setDefaultFont(mainFont()); + doc.drawContents(painter); + } + } + + QTextDocument doc; +}; +#endif // QCP_ITEM_RICH_TEXT diff --git a/plugins/pyqcustomplot/wrapper/qcp.hh b/plugins/pyqcustomplot/wrapper/qcp.hh new file mode 100644 index 0000000000000000000000000000000000000000..7f5417dd2b0ff4a37fcb422baece6e5eccc0081b --- /dev/null +++ b/plugins/pyqcustomplot/wrapper/qcp.hh @@ -0,0 +1,58 @@ +#ifndef WRAPPER_QCP_HH +# define WRAPPER_QCP_HH +# include <qcustomplot.h> + +namespace wrapper { +class PyQCP : public QObject +{ Q_OBJECT + public: + Q_ENUMS(MarginSide AntialiasedElement PlottingHint Interaction ) + Q_FLAGS(MarginSides AntialiasedElements PlottingHints Interactions) + +enum MarginSide { msLeft = QCP::msLeft + ,msRight = QCP::msRight + ,msTop = QCP::msTop + ,msBottom = QCP::msBottom + ,msAll = QCP::msAll + ,msNone = QCP::msNone + }; +Q_DECLARE_FLAGS(MarginSides, MarginSide) + +enum AntialiasedElement { aeAxes = QCP::aeAxes + ,aeGrid = QCP::aeGrid + ,aeSubGrid = QCP::aeSubGrid + ,aeLegend = QCP::aeLegend + ,aeLegendItems = QCP::aeLegendItems + ,aePlottables = QCP::aePlottables + ,aeItems = QCP::aeItems + ,aeScatters = QCP::aeScatters + ,aeErrorBars = QCP::aeErrorBars + ,aeFills = QCP::aeFills + ,aeZeroLine = QCP::aeZeroLine + ,aeAll = QCP::aeAll + ,aeNone = QCP::aeNone + }; +Q_DECLARE_FLAGS(AntialiasedElements, AntialiasedElement) + +enum PlottingHint { phNone = QCP::phNone + ,phFastPolylines = QCP::phFastPolylines + ,phForceRepaint = QCP::phForceRepaint + ,phCacheLabels = QCP::phCacheLabels + }; +Q_DECLARE_FLAGS(PlottingHints, PlottingHint) + +enum Interaction { iRangeDrag = QCP::iRangeDrag + ,iRangeZoom = QCP::iRangeZoom + ,iMultiSelect = QCP::iMultiSelect + ,iSelectPlottables = QCP::iSelectPlottables + ,iSelectAxes = QCP::iSelectAxes + ,iSelectLegend = QCP::iSelectLegend + ,iSelectItems = QCP::iSelectItems + ,iSelectOther = QCP::iSelectOther + }; +Q_DECLARE_FLAGS(Interactions, Interaction) + +}; +} + +#endif // WRAPPER_QCP_HH diff --git a/pyplugins/gepetto/gui/qcp_example.py b/pyplugins/gepetto/gui/qcp_example.py new file mode 100644 index 0000000000000000000000000000000000000000..e1a2174600657008bb12d5a73fc805eca9734bb3 --- /dev/null +++ b/pyplugins/gepetto/gui/qcp_example.py @@ -0,0 +1,32 @@ +from PythonQt import QtGui +from PythonQt.QCustomPlot import QCustomPlot, QCPItemTracer, QCPItemRichText, QCP + +class Plugin (QtGui.QDockWidget): + def __init__ (self, mainWindow, flags = None): + if flags is None: + super(Plugin, self).__init__ ("QCP example plugin", mainWindow) + else: + super(Plugin, self).__init__ ("QCP example plugin", mainWindow, flags) + self.setObjectName("QCP example plugin") + + self.main = mainWindow + self.qcp = QCustomPlot () + self.qcp.setInteraction (QCP.iRangeDrag, True) + self.qcp.setInteraction (QCP.iRangeZoom, True) + self.setWidget (self.qcp) + + self.graph = self.qcp.addGraph () + self.graph.setData ([0,1,2,3], [0.1,0.3,0.2,0]) + self.qcp.replot() + + self.tracer = QCPItemTracer (self.qcp) + self.tracer.graph = self.graph + self.tracer.graphKey = 0 + self.tracer.style = 3 + + self.text = QCPItemRichText (self.qcp) + self.text.text = u"q<sub>0,0</sub>" + self.text.position("position").setParentAnchor(self.tracer.anchor("position")) + self.text.position("position").setCoords (0, -20) + + self.graph.setData ([0,1,2,3], [1,0.3,0.2,0])