From 0e79943099b7b6a4997d6a1686fe8ce5238a2aeb Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 7 Mar 2014 15:21:25 +0100 Subject: [PATCH 01/10] Implementation of zoomin by drawing a rectangle around a zone --- src/global.h | 2 + src/layoutelements/layoutelement-axisrect.cpp | 91 +++++++++++++------ src/layoutelements/layoutelement-axisrect.h | 1 + 3 files changed, 67 insertions(+), 27 deletions(-) diff --git a/src/global.h b/src/global.h index cd929f22..9bbb4f8a 100644 --- a/src/global.h +++ b/src/global.h @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) @@ -138,6 +139,7 @@ enum Interaction { iRangeDrag = 0x001 ///< 0x001 Axis ranges ar ,iSelectLegend = 0x020 ///< 0x020 Legends are selectable (or their child items, see QCPLegend::setSelectableParts) ,iSelectItems = 0x040 ///< 0x040 Items are selectable (Rectangles, Arrows, Textitems, etc. see \ref QCPAbstractItem) ,iSelectOther = 0x080 ///< 0x080 All other objects are selectable (e.g. your own derived layerables, the plot title,...) + ,iZoomRect = 0x100 ///< 0x100 Acis ranges are zoomable by drawing a rectangle on a zone (see \ref QCPAxisRect::setRangeZoom, \ref QCPAxisRect::setRangeZoomAxes) }; Q_DECLARE_FLAGS(Interactions, Interaction) diff --git a/src/layoutelements/layoutelement-axisrect.cpp b/src/layoutelements/layoutelement-axisrect.cpp index e7247569..46892293 100644 --- a/src/layoutelements/layoutelement-axisrect.cpp +++ b/src/layoutelements/layoutelement-axisrect.cpp @@ -172,7 +172,8 @@ QCPAxisRect::QCPAxisRect(QCustomPlot *parentPlot, bool setupDefaultAxes) : mRangeZoom(Qt::Horizontal|Qt::Vertical), mRangeZoomFactorHorz(0.85), mRangeZoomFactorVert(0.85), - mDragging(false) + mDragging(false), + mZoomRubber(new QRubberBand(QRubberBand::Rectangle, parentPlot)) { mInsetLayout->initializeParentPlot(mParentPlot); mInsetLayout->setParentLayerable(this); @@ -204,6 +205,8 @@ QCPAxisRect::QCPAxisRect(QCustomPlot *parentPlot, bool setupDefaultAxes) : xAxis2->grid()->setVisible(false); yAxis2->grid()->setVisible(false); } + + mZoomRubber->hide(); } QCPAxisRect::~QCPAxisRect() @@ -873,7 +876,7 @@ int QCPAxisRect::calculateAutoMargin(QCP::MarginSide side) void QCPAxisRect::mousePressEvent(QMouseEvent *event) { mDragStart = event->pos(); // need this even when not LeftButton is pressed, to determine in releaseEvent whether it was a full click (no position change between press and release) - if (event->buttons() & Qt::LeftButton) + if (event->button() == Qt::LeftButton) { mDragging = true; // initialize antialiasing backup in case we start dragging: @@ -890,6 +893,11 @@ void QCPAxisRect::mousePressEvent(QMouseEvent *event) if (mRangeDragVertAxis) mDragStartVertRange = mRangeDragVertAxis.data()->range(); } + else if (mParentPlot->interactions().testFlag(QCP::iZoomRect)) + { + mZoomRubber->setGeometry(QRect(mDragStart, QSize(0, 0))); + mZoomRubber->show(); + } } } @@ -903,43 +911,50 @@ void QCPAxisRect::mousePressEvent(QMouseEvent *event) void QCPAxisRect::mouseMoveEvent(QMouseEvent *event) { // Mouse range dragging interaction: - if (mDragging && mParentPlot->interactions().testFlag(QCP::iRangeDrag)) + if (mDragging) { - if (mRangeDrag.testFlag(Qt::Horizontal)) + if (mParentPlot->interactions().testFlag(QCP::iRangeDrag)) { - if (QCPAxis *rangeDragHorzAxis = mRangeDragHorzAxis.data()) + if (mRangeDrag.testFlag(Qt::Horizontal)) { - if (rangeDragHorzAxis->mScaleType == QCPAxis::stLinear) - { - double diff = rangeDragHorzAxis->pixelToCoord(mDragStart.x()) - rangeDragHorzAxis->pixelToCoord(event->pos().x()); - rangeDragHorzAxis->setRange(mDragStartHorzRange.lower+diff, mDragStartHorzRange.upper+diff); - } else if (rangeDragHorzAxis->mScaleType == QCPAxis::stLogarithmic) + if (QCPAxis *rangeDragHorzAxis = mRangeDragHorzAxis.data()) { - double diff = rangeDragHorzAxis->pixelToCoord(mDragStart.x()) / rangeDragHorzAxis->pixelToCoord(event->pos().x()); - rangeDragHorzAxis->setRange(mDragStartHorzRange.lower*diff, mDragStartHorzRange.upper*diff); + if (rangeDragHorzAxis->mScaleType == QCPAxis::stLinear) + { + double diff = rangeDragHorzAxis->pixelToCoord(mDragStart.x()) - rangeDragHorzAxis->pixelToCoord(event->pos().x()); + rangeDragHorzAxis->setRange(mDragStartHorzRange.lower+diff, mDragStartHorzRange.upper+diff); + } else if (rangeDragHorzAxis->mScaleType == QCPAxis::stLogarithmic) + { + double diff = rangeDragHorzAxis->pixelToCoord(mDragStart.x()) / rangeDragHorzAxis->pixelToCoord(event->pos().x()); + rangeDragHorzAxis->setRange(mDragStartHorzRange.lower*diff, mDragStartHorzRange.upper*diff); + } } } - } - if (mRangeDrag.testFlag(Qt::Vertical)) - { - if (QCPAxis *rangeDragVertAxis = mRangeDragVertAxis.data()) + if (mRangeDrag.testFlag(Qt::Vertical)) { - if (rangeDragVertAxis->mScaleType == QCPAxis::stLinear) - { - double diff = rangeDragVertAxis->pixelToCoord(mDragStart.y()) - rangeDragVertAxis->pixelToCoord(event->pos().y()); - rangeDragVertAxis->setRange(mDragStartVertRange.lower+diff, mDragStartVertRange.upper+diff); - } else if (rangeDragVertAxis->mScaleType == QCPAxis::stLogarithmic) + if (QCPAxis *rangeDragVertAxis = mRangeDragVertAxis.data()) { - double diff = rangeDragVertAxis->pixelToCoord(mDragStart.y()) / rangeDragVertAxis->pixelToCoord(event->pos().y()); - rangeDragVertAxis->setRange(mDragStartVertRange.lower*diff, mDragStartVertRange.upper*diff); + if (rangeDragVertAxis->mScaleType == QCPAxis::stLinear) + { + double diff = rangeDragVertAxis->pixelToCoord(mDragStart.y()) - rangeDragVertAxis->pixelToCoord(event->pos().y()); + rangeDragVertAxis->setRange(mDragStartVertRange.lower+diff, mDragStartVertRange.upper+diff); + } else if (rangeDragVertAxis->mScaleType == QCPAxis::stLogarithmic) + { + double diff = rangeDragVertAxis->pixelToCoord(mDragStart.y()) / rangeDragVertAxis->pixelToCoord(event->pos().y()); + rangeDragVertAxis->setRange(mDragStartVertRange.lower*diff, mDragStartVertRange.upper*diff); + } } } + if (mRangeDrag != 0) // if either vertical or horizontal drag was enabled, do a replot + { + if (mParentPlot->noAntialiasingOnDrag()) + mParentPlot->setNotAntialiasedElements(QCP::aeAll); + mParentPlot->replot(); + } } - if (mRangeDrag != 0) // if either vertical or horizontal drag was enabled, do a replot + else if (mParentPlot->interactions().testFlag(QCP::iZoomRect)) { - if (mParentPlot->noAntialiasingOnDrag()) - mParentPlot->setNotAntialiasedElements(QCP::aeAll); - mParentPlot->replot(); + mZoomRubber->setGeometry(QRect(mDragStart, event->pos()).normalized()); } } } @@ -954,6 +969,28 @@ void QCPAxisRect::mouseReleaseEvent(QMouseEvent *event) mParentPlot->setAntialiasedElements(mAADragBackup); mParentPlot->setNotAntialiasedElements(mNotAADragBackup); } + + if (event->button() == Qt::LeftButton && mParentPlot->interactions().testFlag(QCP::iZoomRect)) + { + mZoomRubber->hide(); + QRect rect = mZoomRubber->geometry(); + if(rect.width() > 10 && rect.height() > 10) // protection against unvolotary moves + { + if (QCPAxis *rangeDragHorzAxis = mRangeZoomHorzAxis.data()) + { + double left = rangeDragHorzAxis->pixelToCoord(rect.left()); + double right = rangeDragHorzAxis->pixelToCoord(rect.right()); + rangeDragHorzAxis->setRange(left, right); + } + if (QCPAxis *rangeDragVertAxis = mRangeZoomVertAxis.data()) + { + double top = rangeDragVertAxis->pixelToCoord(rect.top()); + double bottom = rangeDragVertAxis->pixelToCoord(rect.bottom()); + rangeDragVertAxis->setRange(bottom, top); + } + mParentPlot->replot(); + } + } } /*! \internal diff --git a/src/layoutelements/layoutelement-axisrect.h b/src/layoutelements/layoutelement-axisrect.h index 0fea4231..b06e77b2 100644 --- a/src/layoutelements/layoutelement-axisrect.h +++ b/src/layoutelements/layoutelement-axisrect.h @@ -124,6 +124,7 @@ protected: QPoint mDragStart; bool mDragging; QHash > mAxes; + QRubberBand *mZoomRubber; // reimplemented virtual methods: virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const; -- GitLab From be7d6840389cf79a7f25128157b0491512eedf8e Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 10 Mar 2014 16:15:13 +0100 Subject: [PATCH 02/10] Basic working externalized interaction (only zoom range yet) --- src/core.cpp | 81 ++++++- src/core.h | 6 +- src/interaction.cpp | 96 ++++++++ src/interaction.h | 82 +++++++ src/interactions/interaction-zoomrange.cpp | 218 ++++++++++++++++++ src/interactions/interaction-zoomrange.h | 89 +++++++ src/layoutelements/layoutelement-axisrect.cpp | 136 +---------- src/layoutelements/layoutelement-axisrect.h | 14 +- .../layoutelement-colorscale.cpp | 34 --- src/layoutelements/layoutelement-colorscale.h | 2 - 10 files changed, 566 insertions(+), 192 deletions(-) create mode 100644 src/interaction.cpp create mode 100644 src/interaction.h create mode 100644 src/interactions/interaction-zoomrange.cpp create mode 100644 src/interactions/interaction-zoomrange.h diff --git a/src/core.cpp b/src/core.cpp index 5cdeb4de..79147032 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -36,6 +36,8 @@ #include "plottable.h" #include "plottables/plottable-graph.h" #include "item.h" +#include "interaction.h" +#include "interactions/interaction-zoomrange.h" /*! \mainpage %QCustomPlot 1.2.0-beta Documentation @@ -541,7 +543,7 @@ QCustomPlot::QCustomPlot(QWidget *parent) : mAutoAddPlottableToLegend(true), mAntialiasedElements(QCP::aeNone), mNotAntialiasedElements(QCP::aeNone), - mInteractions(0), + mInteractions(), mSelectionTolerance(8), mNoAntialiasingOnDrag(false), mBackgroundBrush(Qt::white, Qt::SolidPattern), @@ -776,7 +778,20 @@ void QCustomPlot::setAutoAddPlottableToLegend(bool on) */ void QCustomPlot::setInteractions(const QCP::Interactions &interactions) { - mInteractions = interactions; + //mInteractions = interactions; + + foreach(QCPAbstractInteraction *interaction, mInteractions) + { + delete interaction; + } + mInteractions.clear(); + + if(interactions.testFlag(QCP::iRangeZoom)) + { + QCPInteractionZoomRange *interaction = new QCPInteractionZoomRange(this); + interaction->setAxes(xAxis, yAxis); + mInteractions << interaction; + } } /*! @@ -788,10 +803,15 @@ void QCustomPlot::setInteractions(const QCP::Interactions &interactions) */ void QCustomPlot::setInteraction(const QCP::Interaction &interaction, bool enabled) { - if (!enabled && mInteractions.testFlag(interaction)) + /*if (!enabled && mInteractions.testFlag(interaction)) mInteractions &= ~interaction; else if (enabled && !mInteractions.testFlag(interaction)) - mInteractions |= interaction; + mInteractions |= interaction;*/ +} + +void QCustomPlot::addInteraction(QCPAbstractInteraction *interaction) +{ + mInteractions << interaction; } /*! @@ -2189,6 +2209,7 @@ void QCustomPlot::mouseDoubleClickEvent(QMouseEvent *event) { emit mouseDoubleClick(event); + /* QVariant details; QCPLayerable *clickedLayerable = layerableAt(event->pos(), false, &details); @@ -2215,7 +2236,7 @@ void QCustomPlot::mouseDoubleClickEvent(QMouseEvent *event) { mMouseEventElement->mouseReleaseEvent(event); mMouseEventElement = 0; - } + }*/ //QWidget::mouseDoubleClickEvent(event); don't call base class implementation because it would just cause a mousePress/ReleaseEvent, which we don't want. } @@ -2229,13 +2250,27 @@ void QCustomPlot::mouseDoubleClickEvent(QMouseEvent *event) */ void QCustomPlot::mousePressEvent(QMouseEvent *event) { + qDebug("coucou"); + emit mousePress(event); + + /* mMousePressPos = event->pos(); // need this to determine in releaseEvent whether it was a click (no position change between press and release) // call event of affected layout element: mMouseEventElement = layoutElementAt(event->pos()); if (mMouseEventElement) mMouseEventElement->mousePressEvent(event); + */ + + foreach(QCPAbstractInteraction *interaction, mInteractions) + { + if(interaction->mousePressEvent(event)) + { + event->accept(); + break; + } + } QWidget::mousePressEvent(event); } @@ -2253,9 +2288,20 @@ void QCustomPlot::mouseMoveEvent(QMouseEvent *event) { emit mouseMove(event); + /* // call event of affected layout element: if (mMouseEventElement) mMouseEventElement->mouseMoveEvent(event); + */ + + foreach(QCPAbstractInteraction *interaction, mInteractions) + { + if(interaction->mouseMoveEvent(event)) + { + event->accept(); + break; + } + } QWidget::mouseMoveEvent(event); } @@ -2276,7 +2322,7 @@ void QCustomPlot::mouseMoveEvent(QMouseEvent *event) */ void QCustomPlot::mouseReleaseEvent(QMouseEvent *event) { - emit mouseRelease(event); + /*emit mouseRelease(event); bool doReplot = false; if ((mMousePressPos-event->pos()).manhattanLength() < 5) // determine whether it was a click operation @@ -2341,7 +2387,16 @@ void QCustomPlot::mouseReleaseEvent(QMouseEvent *event) } if (doReplot || noAntialiasingOnDrag()) - replot(); + replot();*/ + + foreach(QCPAbstractInteraction *interaction, mInteractions) + { + if(interaction->mouseReleaseEvent(event)) + { + event->accept(); + break; + } + } QWidget::mouseReleaseEvent(event); } @@ -2355,10 +2410,20 @@ void QCustomPlot::mouseReleaseEvent(QMouseEvent *event) void QCustomPlot::wheelEvent(QWheelEvent *event) { emit mouseWheel(event); - + /* // call event of affected layout element: if (QCPLayoutElement *el = layoutElementAt(event->pos())) el->wheelEvent(event); + */ + + foreach(QCPAbstractInteraction *interaction, mInteractions) + { + if(interaction->mouseWheelEvent(event)) + { + event->accept(); + break; + } + } QWidget::wheelEvent(event); } diff --git a/src/core.h b/src/core.h index 7f8b2f07..c64f2b9c 100644 --- a/src/core.h +++ b/src/core.h @@ -38,6 +38,7 @@ class QCPGraph; class QCPPlotTitle; class QCPLegend; class QCPAbstractLegendItem; +class QCPAbstractInteraction; class QCP_LIB_DECL QCustomPlot : public QWidget { @@ -86,7 +87,7 @@ public: QCP::AntialiasedElements antialiasedElements() const { return mAntialiasedElements; } QCP::AntialiasedElements notAntialiasedElements() const { return mNotAntialiasedElements; } bool autoAddPlottableToLegend() const { return mAutoAddPlottableToLegend; } - const QCP::Interactions interactions() const { return mInteractions; } + const QCP::Interactions interactions() const { return 0; } int selectionTolerance() const { return mSelectionTolerance; } bool noAntialiasingOnDrag() const { return mNoAntialiasingOnDrag; } QCP::PlottingHints plottingHints() const { return mPlottingHints; } @@ -106,6 +107,7 @@ public: void setAutoAddPlottableToLegend(bool on); void setInteractions(const QCP::Interactions &interactions); void setInteraction(const QCP::Interaction &interaction, bool enabled=true); + void addInteraction(QCPAbstractInteraction *interaction); void setSelectionTolerance(int pixels); void setNoAntialiasingOnDrag(bool enabled); void setPlottingHints(const QCP::PlottingHints &hints); @@ -213,7 +215,7 @@ protected: QList mItems; QList mLayers; QCP::AntialiasedElements mAntialiasedElements, mNotAntialiasedElements; - QCP::Interactions mInteractions; + QList mInteractions; int mSelectionTolerance; bool mNoAntialiasingOnDrag; QBrush mBackgroundBrush; diff --git a/src/interaction.cpp b/src/interaction.cpp new file mode 100644 index 00000000..e8ba7b39 --- /dev/null +++ b/src/interaction.cpp @@ -0,0 +1,96 @@ +/*************************************************************************** +** ** +** QCustomPlot, an easy to use, modern plotting widget for Qt ** +** Copyright (C) 2011, 2012, 2013, 2014 Emanuel Eichhammer ** +** ** +** This program is free software: you can redistribute it and/or modify ** +** it under the terms of the GNU General Public License as published by ** +** the Free Software Foundation, either version 3 of the License, or ** +** (at your option) any later version. ** +** ** +** This program is distributed in the hope that it will be useful, ** +** but WITHOUT ANY WARRANTY; without even the implied warranty of ** +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** +** GNU General Public License for more details. ** +** ** +** You should have received a copy of the GNU General Public License ** +** along with this program. If not, see http://www.gnu.org/licenses/. ** +** ** +**************************************************************************** +** Author: Erwan Mathieu ** +** Website/Contact: http://www.qcustomplot.com/ ** +** Date: 10.03.14 ** +** Version: 1.2.0-beta ** +****************************************************************************/ + +#include "interaction.h" + +#include "core.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////// QCPAbstractInteraction +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*! \class QCPAbstractInteraction + \brief +*/ + +QCPAbstractInteraction::QCPAbstractInteraction(QCustomPlot *parentPlot) : + QObject(parentPlot), + mParentPlot(parentPlot), + mActive(false) +{ +} + +QCPAbstractInteraction::~QCPAbstractInteraction() +{ +} + +bool QCPAbstractInteraction::mouseDoubleClickEvent(QMouseEvent *event) +{ + Q_UNUSED(event) + return false; +} + +bool QCPAbstractInteraction::mousePressEvent(QMouseEvent *event) +{ + Q_UNUSED(event) + return false; +} + +bool QCPAbstractInteraction::mouseMoveEvent(QMouseEvent *event) +{ + Q_UNUSED(event) + return false; +} + +bool QCPAbstractInteraction::mouseReleaseEvent(QMouseEvent *event) +{ + Q_UNUSED(event) + return false; +} + +bool QCPAbstractInteraction::mouseWheelEvent(QWheelEvent *event) +{ + Q_UNUSED(event) + return false; +} + +QCPAbstractInteraction::MouseButton QCPAbstractInteraction::toMouseButton(Qt::MouseButton button) +{ + switch(button) + { + case Qt::LeftButton: + return mbLeft; + case Qt::RightButton: + return mbRight; + case Qt::MiddleButton: + return mbMiddle; + case Qt::XButton1: + return mbXButton1; + case Qt::XButton2: + return mbXButton2; + default: + return mbNone; + } +} diff --git a/src/interaction.h b/src/interaction.h new file mode 100644 index 00000000..b4b08904 --- /dev/null +++ b/src/interaction.h @@ -0,0 +1,82 @@ +/*************************************************************************** +** ** +** QCustomPlot, an easy to use, modern plotting widget for Qt ** +** Copyright (C) 2011, 2012, 2013, 2014 Emanuel Eichhammer ** +** ** +** This program is free software: you can redistribute it and/or modify ** +** it under the terms of the GNU General Public License as published by ** +** the Free Software Foundation, either version 3 of the License, or ** +** (at your option) any later version. ** +** ** +** This program is distributed in the hope that it will be useful, ** +** but WITHOUT ANY WARRANTY; without even the implied warranty of ** +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** +** GNU General Public License for more details. ** +** ** +** You should have received a copy of the GNU General Public License ** +** along with this program. If not, see http://www.gnu.org/licenses/. ** +** ** +**************************************************************************** +** Author: Erwan Mathieu ** +** Website/Contact: http://www.qcustomplot.com/ ** +** Date: 07.03.14 ** +** Version: 1.2.0-beta ** +****************************************************************************/ + +#ifndef QCP_INTERACTION_H +#define QCP_INTERACTION_H + +#include "global.h" +#include "layer.h" +#include "axis.h" + +class QCustomPlot; + + +class QCP_LIB_DECL QCPAbstractInteraction : public QObject +{ + Q_OBJECT +public: + /*! + Defines the pressed mouse buttons + */ + enum MouseButton { mbNone ///< No button + ,mbLeft ///< The mouse standard left button + ,mbRight ///< The mouse standard right button + ,mbMiddle ///< The mouse middle button, usually triggered by pressing the wheel + ,mbWheelUp ///< Pseudo-button, use when the wheel has been moved up + ,mbWheelDown ///< Pseudo-button, use when the wheel has been moved down + ,mbXButton1 ///< First optional mouse button, usually located on the side + ,mbXButton2 ///< Seconcd optional mouse button, usually located on the side + }; + + QCPAbstractInteraction(QCustomPlot *parentPlot); + virtual ~QCPAbstractInteraction(); + + // getters: + QCustomPlot *parentPlot() const { return mParentPlot; } + bool active() const { return mActive; } + + // setters: + void setActive(bool active) { mActive = active; } + + // introduced virtual method: + virtual bool mouseDoubleClickEvent(QMouseEvent *event); + virtual bool mousePressEvent(QMouseEvent *event); + virtual bool mouseMoveEvent(QMouseEvent *event); + virtual bool mouseReleaseEvent(QMouseEvent *event); + virtual bool mouseWheelEvent(QWheelEvent *event); + + // static methods: + MouseButton toMouseButton(Qt::MouseButton button); + +protected: + // property members: + QCustomPlot *mParentPlot; + bool mActive; + +private: + Q_DISABLE_COPY(QCPAbstractInteraction) +}; + +#endif // QCP_INTERACTION_H diff --git a/src/interactions/interaction-zoomrange.cpp b/src/interactions/interaction-zoomrange.cpp new file mode 100644 index 00000000..9f191b49 --- /dev/null +++ b/src/interactions/interaction-zoomrange.cpp @@ -0,0 +1,218 @@ +/*************************************************************************** +** ** +** QCustomPlot, an easy to use, modern plotting widget for Qt ** +** Copyright (C) 2011, 2012, 2013, 2014 Emanuel Eichhammer ** +** ** +** This program is free software: you can redistribute it and/or modify ** +** it under the terms of the GNU General Public License as published by ** +** the Free Software Foundation, either version 3 of the License, or ** +** (at your option) any later version. ** +** ** +** This program is distributed in the hope that it will be useful, ** +** but WITHOUT ANY WARRANTY; without even the implied warranty of ** +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** +** GNU General Public License for more details. ** +** ** +** You should have received a copy of the GNU General Public License ** +** along with this program. If not, see http://www.gnu.org/licenses/. ** +** ** +**************************************************************************** +** Author: Erwan Mathieu ** +** Website/Contact: http://www.qcustomplot.com/ ** +** Date: 10.03.14 ** +** Version: 1.2.0-beta ** +****************************************************************************/ + +#include "interaction-zoomrange.h" + +#include "axis.h" +#include "core.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////// QCPInteractionZoomRange +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*! \class QCPInteractionZoomRange + \brief Interaction for mouse zoom in/out using the wheel or buttons. If orientations is + Qt::Horizontal, Qt::Vertical or both, the ranges of the defined axes are scaled. The center of + the scaling operation is the current cursor position inside the axis rect. The scaling factor is + dependant on the mouse wheel delta (which direction the wheel was rotated) to provide a natural + zooming feel. The Strength of the zoom can be controlled via \ref setFactor. To zoom in/out using + other mouse buttons, you may call the \ref setButtonZoomIn and \ref setButtonZoomOut methods. + + Note, that event->delta() is usually +/-120 for single rotation steps. However, if the mouse + wheel is turned rapidly, many steps may bunch up to one event, so the event->delta() may then be + multiples of 120. This is taken into account here, by calculating \a wheelSteps and using it as + exponent of the range zoom factor. This takes care of the wheel direction automatically, by + inverting the factor, when the wheel step is negative (f^-1 = 1/f). +*/ + +/* start documentation of inline functions */ + +/*! \fn void QCPInteractionZoomRange::setOrientations(Qt::Orientations orientations) + + Sets which axis orientation may be zoomed by the user with the mouse wheel. What orientation + corresponds to which specific axis can be set with \ref setRangeZoomAxes(QCPAxis *horizontal, + QCPAxis *vertical). By default, the horizontal axis is the bottom axis (xAxis) and the vertical + axis is the left axis (yAxis). + + To disable range zooming entirely, pass 0 as \a orientations or remove \ref QCP::iRangeZoom from \ref + QCustomPlot::setInteractions. To enable range zooming for both directions, pass Qt::Horizontal | + Qt::Vertical as \a orientations. + + In addition to setting \a orientations to a non-zero value, make sure \ref QCustomPlot::setInteractions + contains \ref QCP::iRangeZoom to enable the range zooming interaction. + + \see setRangeZoomFactor, setRangeZoomAxes, setRangeDrag +*/ + +/*! \fn void QCPInteractionZoomRange::setFactorHorz(double factor) + + Sets how strong step of the mouse button zooms in/out on the horizontal axis. The two methods + \a setFactorHorz and \a setFactorVert provide a way to let the horizontal axis zoom at different + rates than the vertical axis. Which axis is horizontal and which is vertical, can be set + with \ref setAxes. + + \see setFactorVert, setFactor +*/ + +/*! \fn void QCPInteractionZoomRange::setFactorVert(double factor) + + Sets how strong step of the mouse button zooms in/out on the vertical axis. The two methods + \a setFactorHorz and \a setFactorVert provide a way to let the horizontal axis zoom at different + rates than the vertical axis. Which axis is horizontal and which is vertical, can be set + with \ref setAxes. + + \see setFactorHorz, setFactor +*/ + +/*! \fn void QCPInteractionZoomRange::setFactor(double factor) + + Sets how strong step of the mouse button zooms in/out on both the horizontal and vertical axis. + The \a factor should be lesser than 1, or the zoom will be inverted. + + \see setFactorHorz, setFactorVert +*/ + +/* end documentation of inline functions */ + +QCPInteractionZoomRange::QCPInteractionZoomRange(QCustomPlot *parentPlot) : + QCPAbstractInteraction(parentPlot), + mButtonZoomIn(mbWheelUp), + mButtonZoomOut(mbWheelDown), + mOrientations(Qt::Horizontal|Qt::Vertical), + mFactorHorz(0.85), + mFactorVert(0.85), + mMousePressPos(), + mAxisHorz(), + mAxisVert() +{ +} + +QCPInteractionZoomRange::~QCPInteractionZoomRange() +{ +} + +/*! + Returns the range zoom axis of the \a orientation provided. + + \see setRangeZoomAxes +*/ +QCPAxis *QCPInteractionZoomRange::rangeZoomAxis(Qt::Orientation orientation) +{ + return orientation == Qt::Horizontal ? mAxisHorz : mAxisVert; +} + +/*! + Returns the range zoom factor of the \a orientation provided. + + \see setRangeZoomFactor +*/ +double QCPInteractionZoomRange::rangeZoomFactor(Qt::Orientation orientation) const +{ + return orientation == Qt::Horizontal ? mFactorHorz : mFactorVert; +} + +/*! + Sets the axes whose range will be zoomed when \ref setRangeZoom enables mouse wheel zooming on the + QCustomPlot widget. The two axes can be zoomed with different strengths, when different factors + are passed to \ref setRangeZoomFactor(double horizontalFactor, double verticalFactor). + + \see setRangeDragAxes +*/ +void QCPInteractionZoomRange::setAxes(QCPAxis *horizontal, QCPAxis *vertical) +{ + mAxisHorz = horizontal; + mAxisVert = vertical; +} + +bool QCPInteractionZoomRange::mousePressEvent(QMouseEvent *event) +{ + MouseButton button = toMouseButton(event->button()); + if(button == mButtonZoomIn || button == mButtonZoomOut) + { + mMousePressPos = event->pos(); + } + + return false; +} + +bool QCPInteractionZoomRange::mouseReleaseEvent(QMouseEvent *event) +{ + MouseButton button = toMouseButton(event->button()); + if(button == mButtonZoomIn || button == mButtonZoomOut) + { + if ((mMousePressPos - event->pos()).manhattanLength() < 5) // determine whether it was a click operation + { + return doZoom(event->pos(), button == mButtonZoomIn ? 1 : -1); + } + } + + return false; +} + +bool QCPInteractionZoomRange::mouseWheelEvent(QWheelEvent *event) +{ + double wheelDelta = event->delta() / 120.0; // a single step delta is +/-120 usually + double wise = 0; + + if(wheelDelta > 0) + { + if(mButtonZoomIn == mbWheelUp) + wise = 1; + else if(mButtonZoomOut == mbWheelUp) + wise = -1; + } + else + { + if(mButtonZoomIn == mbWheelDown) + wise = -1; + else if(mButtonZoomOut == mbWheelDown) + wise = 1; + } + + if(!qFuzzyIsNull(wise)) + return doZoom(event->pos(), wheelDelta * wise); + + return false; +} + +bool QCPInteractionZoomRange::doZoom(const QPoint &pos, double steps) +{ + bool scale = false; + if (!mAxisHorz.isNull() && mOrientations.testFlag(Qt::Horizontal)) + { + mAxisHorz->scaleRange(pow(mFactorHorz, steps), mAxisHorz->pixelToCoord(pos.x())); + scale = true; + } + if (!mAxisVert.isNull() && mOrientations.testFlag(Qt::Vertical)) + { + mAxisVert->scaleRange(pow(mFactorVert, steps), mAxisVert->pixelToCoord(pos.y())); + scale = true; + } + + if(scale) + parentPlot()->replot(); + + return scale; +} diff --git a/src/interactions/interaction-zoomrange.h b/src/interactions/interaction-zoomrange.h new file mode 100644 index 00000000..04b9c801 --- /dev/null +++ b/src/interactions/interaction-zoomrange.h @@ -0,0 +1,89 @@ +/*************************************************************************** +** ** +** QCustomPlot, an easy to use, modern plotting widget for Qt ** +** Copyright (C) 2011, 2012, 2013, 2014 Emanuel Eichhammer ** +** ** +** This program is free software: you can redistribute it and/or modify ** +** it under the terms of the GNU General Public License as published by ** +** the Free Software Foundation, either version 3 of the License, or ** +** (at your option) any later version. ** +** ** +** This program is distributed in the hope that it will be useful, ** +** but WITHOUT ANY WARRANTY; without even the implied warranty of ** +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** +** GNU General Public License for more details. ** +** ** +** You should have received a copy of the GNU General Public License ** +** along with this program. If not, see http://www.gnu.org/licenses/. ** +** ** +**************************************************************************** +** Author: Erwan Mathieu ** +** Website/Contact: http://www.qcustomplot.com/ ** +** Date: 10.03.14 ** +** Version: 1.2.0-beta ** +****************************************************************************/ + +#ifndef QCP_INTERACTION_ZOOMRANGE_H +#define QCP_INTERACTION_ZOOMRANGE_H + +#include "interaction.h" + +class QCPAxis; + + +class QCP_LIB_DECL QCPInteractionZoomRange : public QCPAbstractInteraction +{ + Q_OBJECT + /// \cond INCLUDE_QPROPERTIES + Q_PROPERTY(MouseButton buttonZoomIn READ buttonZoomIn WRITE setButtonZoomIn) + Q_PROPERTY(MouseButton buttonZoomOut READ buttonZoomOut WRITE setButtonZoomOut) + Q_PROPERTY(Qt::Orientations orientations READ orientations WRITE setOrientations) + Q_PROPERTY(double factorHorz READ factorHorz WRITE setFactorHorz) + Q_PROPERTY(double factorVert READ factorVert WRITE setFactorVert) + /// \endcond +public: + QCPInteractionZoomRange(QCustomPlot *parentPlot); + virtual ~QCPInteractionZoomRange(); + + // getters: + MouseButton buttonZoomIn() const { return mButtonZoomIn; } + MouseButton buttonZoomOut() const { return mButtonZoomOut; } + Qt::Orientations orientations() const { return mOrientations; } + double factorHorz() const { return mFactorHorz; } + double factorVert() const { return mFactorVert; } + QCPAxis *rangeZoomAxis(Qt::Orientation orientation); + double rangeZoomFactor(Qt::Orientation orientation) const; + + // setters: + void setButtonZoomIn(MouseButton button) { mButtonZoomIn = button; } + void setButtonZoomOut(MouseButton button) { mButtonZoomOut = button; } + void setOrientations(Qt::Orientations orientations) { mOrientations = orientations; } + void setFactorHorz(double factor) { mFactorHorz = factor; } + void setFactorVert(double factor) { mFactorVert = factor; } + void setFactor(double factor) { setFactorHorz(factor); setFactorVert(factor); } + void setAxes(QCPAxis *horizontal, QCPAxis *vertical); + + // reimplemented virtual method: + virtual bool mousePressEvent(QMouseEvent *event); + virtual bool mouseReleaseEvent(QMouseEvent *event); + virtual bool mouseWheelEvent(QWheelEvent *event); + +protected: + // property members + MouseButton mButtonZoomIn; + MouseButton mButtonZoomOut; + Qt::Orientations mOrientations; + double mFactorHorz, mFactorVert; + QPointer mAxisHorz, mAxisVert; + + // non-property members + QPoint mMousePressPos; + + // non-virtual methods: + bool doZoom(const QPoint &pos, double steps); + +private: + Q_DISABLE_COPY(QCPInteractionZoomRange) +}; + +#endif // QCP_INTERACTION_ZOOMRANGE_H diff --git a/src/layoutelements/layoutelement-axisrect.cpp b/src/layoutelements/layoutelement-axisrect.cpp index 46892293..1510e6c9 100644 --- a/src/layoutelements/layoutelement-axisrect.cpp +++ b/src/layoutelements/layoutelement-axisrect.cpp @@ -169,9 +169,6 @@ QCPAxisRect::QCPAxisRect(QCustomPlot *parentPlot, bool setupDefaultAxes) : mBackgroundScaledMode(Qt::KeepAspectRatioByExpanding), mInsetLayout(new QCPLayoutInset), mRangeDrag(Qt::Horizontal|Qt::Vertical), - mRangeZoom(Qt::Horizontal|Qt::Vertical), - mRangeZoomFactorHorz(0.85), - mRangeZoomFactorVert(0.85), mDragging(false), mZoomRubber(new QRubberBand(QRubberBand::Rectangle, parentPlot)) { @@ -193,7 +190,6 @@ QCPAxisRect::QCPAxisRect(QCustomPlot *parentPlot, bool setupDefaultAxes) : QCPAxis *xAxis2 = addAxis(QCPAxis::atTop); QCPAxis *yAxis2 = addAxis(QCPAxis::atRight); setRangeDragAxes(xAxis, yAxis); - setRangeZoomAxes(xAxis, yAxis); xAxis2->setVisible(false); yAxis2->setVisible(false); xAxis->grid()->setVisible(true); @@ -675,25 +671,6 @@ QCPAxis *QCPAxisRect::rangeDragAxis(Qt::Orientation orientation) return (orientation == Qt::Horizontal ? mRangeDragHorzAxis.data() : mRangeDragVertAxis.data()); } -/*! - Returns the range zoom axis of the \a orientation provided. - - \see setRangeZoomAxes -*/ -QCPAxis *QCPAxisRect::rangeZoomAxis(Qt::Orientation orientation) -{ - return (orientation == Qt::Horizontal ? mRangeZoomHorzAxis.data() : mRangeZoomVertAxis.data()); -} - -/*! - Returns the range zoom factor of the \a orientation provided. - - \see setRangeZoomFactor -*/ -double QCPAxisRect::rangeZoomFactor(Qt::Orientation orientation) -{ - return (orientation == Qt::Horizontal ? mRangeZoomFactorHorz : mRangeZoomFactorVert); -} /*! Sets which axis orientation may be range dragged by the user with mouse interaction. @@ -716,26 +693,6 @@ void QCPAxisRect::setRangeDrag(Qt::Orientations orientations) mRangeDrag = orientations; } -/*! - Sets which axis orientation may be zoomed by the user with the mouse wheel. What orientation - corresponds to which specific axis can be set with \ref setRangeZoomAxes(QCPAxis *horizontal, - QCPAxis *vertical). By default, the horizontal axis is the bottom axis (xAxis) and the vertical - axis is the left axis (yAxis). - - To disable range zooming entirely, pass 0 as \a orientations or remove \ref QCP::iRangeZoom from \ref - QCustomPlot::setInteractions. To enable range zooming for both directions, pass Qt::Horizontal | - Qt::Vertical as \a orientations. - - In addition to setting \a orientations to a non-zero value, make sure \ref QCustomPlot::setInteractions - contains \ref QCP::iRangeZoom to enable the range zooming interaction. - - \see setRangeZoomFactor, setRangeZoomAxes, setRangeDrag -*/ -void QCPAxisRect::setRangeZoom(Qt::Orientations orientations) -{ - mRangeZoom = orientations; -} - /*! Sets the axes whose range will be dragged when \ref setRangeDrag enables mouse range dragging on the QCustomPlot widget. @@ -748,45 +705,6 @@ void QCPAxisRect::setRangeDragAxes(QCPAxis *horizontal, QCPAxis *vertical) mRangeDragVertAxis = vertical; } -/*! - Sets the axes whose range will be zoomed when \ref setRangeZoom enables mouse wheel zooming on the - QCustomPlot widget. The two axes can be zoomed with different strengths, when different factors - are passed to \ref setRangeZoomFactor(double horizontalFactor, double verticalFactor). - - \see setRangeDragAxes -*/ -void QCPAxisRect::setRangeZoomAxes(QCPAxis *horizontal, QCPAxis *vertical) -{ - mRangeZoomHorzAxis = horizontal; - mRangeZoomVertAxis = vertical; -} - -/*! - Sets how strong one rotation step of the mouse wheel zooms, when range zoom was activated with - \ref setRangeZoom. The two parameters \a horizontalFactor and \a verticalFactor provide a way to - let the horizontal axis zoom at different rates than the vertical axis. Which axis is horizontal - and which is vertical, can be set with \ref setRangeZoomAxes. - - When the zoom factor is greater than one, scrolling the mouse wheel backwards (towards the user) - will zoom in (make the currently visible range smaller). For zoom factors smaller than one, the - same scrolling direction will zoom out. -*/ -void QCPAxisRect::setRangeZoomFactor(double horizontalFactor, double verticalFactor) -{ - mRangeZoomFactorHorz = horizontalFactor; - mRangeZoomFactorVert = verticalFactor; -} - -/*! \overload - - Sets both the horizontal and vertical zoom \a factor. -*/ -void QCPAxisRect::setRangeZoomFactor(double factor) -{ - mRangeZoomFactorHorz = factor; - mRangeZoomFactorVert = factor; -} - /*! \internal Draws the background of this axis rect. It may consist of a background fill (a QBrush) and a @@ -976,13 +894,13 @@ void QCPAxisRect::mouseReleaseEvent(QMouseEvent *event) QRect rect = mZoomRubber->geometry(); if(rect.width() > 10 && rect.height() > 10) // protection against unvolotary moves { - if (QCPAxis *rangeDragHorzAxis = mRangeZoomHorzAxis.data()) + if (QCPAxis *rangeDragHorzAxis = mRangeDragHorzAxis.data()) { double left = rangeDragHorzAxis->pixelToCoord(rect.left()); double right = rangeDragHorzAxis->pixelToCoord(rect.right()); rangeDragHorzAxis->setRange(left, right); } - if (QCPAxis *rangeDragVertAxis = mRangeZoomVertAxis.data()) + if (QCPAxis *rangeDragVertAxis = mRangeDragVertAxis.data()) { double top = rangeDragVertAxis->pixelToCoord(rect.top()); double bottom = rangeDragVertAxis->pixelToCoord(rect.bottom()); @@ -992,53 +910,3 @@ void QCPAxisRect::mouseReleaseEvent(QMouseEvent *event) } } } - -/*! \internal - - Event handler for mouse wheel events. If rangeZoom is Qt::Horizontal, Qt::Vertical or both, the - ranges of the axes defined as rangeZoomHorzAxis and rangeZoomVertAxis are scaled. The center of - the scaling operation is the current cursor position inside the axis rect. The scaling factor is - dependant on the mouse wheel delta (which direction the wheel was rotated) to provide a natural - zooming feel. The Strength of the zoom can be controlled via \ref setRangeZoomFactor. - - Note, that event->delta() is usually +/-120 for single rotation steps. However, if the mouse - wheel is turned rapidly, many steps may bunch up to one event, so the event->delta() may then be - multiples of 120. This is taken into account here, by calculating \a wheelSteps and using it as - exponent of the range zoom factor. This takes care of the wheel direction automatically, by - inverting the factor, when the wheel step is negative (f^-1 = 1/f). -*/ -void QCPAxisRect::wheelEvent(QWheelEvent *event) -{ - // Mouse range zooming interaction: - if (mParentPlot->interactions().testFlag(QCP::iRangeZoom)) - { - if (mRangeZoom != 0) - { - double factor; - double wheelSteps = event->delta()/120.0; // a single step delta is +/-120 usually - if (mRangeZoom.testFlag(Qt::Horizontal)) - { - factor = pow(mRangeZoomFactorHorz, wheelSteps); - if (mRangeZoomHorzAxis.data()) - mRangeZoomHorzAxis.data()->scaleRange(factor, mRangeZoomHorzAxis.data()->pixelToCoord(event->pos().x())); - } - if (mRangeZoom.testFlag(Qt::Vertical)) - { - factor = pow(mRangeZoomFactorVert, wheelSteps); - if (mRangeZoomVertAxis.data()) - mRangeZoomVertAxis.data()->scaleRange(factor, mRangeZoomVertAxis.data()->pixelToCoord(event->pos().y())); - } - mParentPlot->replot(); - } - } -} - - - - - - - - - - diff --git a/src/layoutelements/layoutelement-axisrect.h b/src/layoutelements/layoutelement-axisrect.h index b06e77b2..d4f496d6 100644 --- a/src/layoutelements/layoutelement-axisrect.h +++ b/src/layoutelements/layoutelement-axisrect.h @@ -45,7 +45,6 @@ class QCP_LIB_DECL QCPAxisRect : public QCPLayoutElement Q_PROPERTY(bool backgroundScaled READ backgroundScaled WRITE setBackgroundScaled) Q_PROPERTY(Qt::AspectRatioMode backgroundScaledMode READ backgroundScaledMode WRITE setBackgroundScaledMode) Q_PROPERTY(Qt::Orientations rangeDrag READ rangeDrag WRITE setRangeDrag) - Q_PROPERTY(Qt::Orientations rangeZoom READ rangeZoom WRITE setRangeZoom) /// \endcond public: explicit QCPAxisRect(QCustomPlot *parentPlot, bool setupDefaultAxes=true); @@ -56,10 +55,7 @@ public: bool backgroundScaled() const { return mBackgroundScaled; } Qt::AspectRatioMode backgroundScaledMode() const { return mBackgroundScaledMode; } Qt::Orientations rangeDrag() const { return mRangeDrag; } - Qt::Orientations rangeZoom() const { return mRangeZoom; } QCPAxis *rangeDragAxis(Qt::Orientation orientation); - QCPAxis *rangeZoomAxis(Qt::Orientation orientation); - double rangeZoomFactor(Qt::Orientation orientation); // setters: void setBackground(const QPixmap &pm); @@ -68,11 +64,7 @@ public: void setBackgroundScaled(bool scaled); void setBackgroundScaledMode(Qt::AspectRatioMode mode); void setRangeDrag(Qt::Orientations orientations); - void setRangeZoom(Qt::Orientations orientations); void setRangeDragAxes(QCPAxis *horizontal, QCPAxis *vertical); - void setRangeZoomAxes(QCPAxis *horizontal, QCPAxis *vertical); - void setRangeZoomFactor(double horizontalFactor, double verticalFactor); - void setRangeZoomFactor(double factor); // non-property methods: int axisCount(QCPAxis::AxisType type) const; @@ -115,9 +107,8 @@ protected: bool mBackgroundScaled; Qt::AspectRatioMode mBackgroundScaledMode; QCPLayoutInset *mInsetLayout; - Qt::Orientations mRangeDrag, mRangeZoom; - QPointer mRangeDragHorzAxis, mRangeDragVertAxis, mRangeZoomHorzAxis, mRangeZoomVertAxis; - double mRangeZoomFactorHorz, mRangeZoomFactorVert; + Qt::Orientations mRangeDrag; + QPointer mRangeDragHorzAxis, mRangeDragVertAxis; // non-property members: QCPRange mDragStartHorzRange, mDragStartVertRange; QCP::AntialiasedElements mAADragBackup, mNotAADragBackup; @@ -134,7 +125,6 @@ protected: virtual void mousePressEvent(QMouseEvent *event); virtual void mouseMoveEvent(QMouseEvent *event); virtual void mouseReleaseEvent(QMouseEvent *event); - virtual void wheelEvent(QWheelEvent *event); // non-property methods: void drawBackground(QCPPainter *painter); diff --git a/src/layoutelements/layoutelement-colorscale.cpp b/src/layoutelements/layoutelement-colorscale.cpp index a7305978..6b4ddb8d 100644 --- a/src/layoutelements/layoutelement-colorscale.cpp +++ b/src/layoutelements/layoutelement-colorscale.cpp @@ -171,20 +171,6 @@ bool QCPColorScale::rangeDrag() const mAxisRect.data()->rangeDragAxis(QCPAxis::orientation(mType))->orientation() == QCPAxis::orientation(mType); } -/* undocumented getter */ -bool QCPColorScale::rangeZoom() const -{ - if (!mAxisRect) - { - qDebug() << Q_FUNC_INFO << "internal axis rect was deleted"; - return false; - } - - return mAxisRect.data()->rangeZoom().testFlag(QCPAxis::orientation(mType)) && - mAxisRect.data()->rangeZoomAxis(QCPAxis::orientation(mType)) && - mAxisRect.data()->rangeZoomAxis(QCPAxis::orientation(mType))->orientation() == QCPAxis::orientation(mType); -} - /*! Sets at which side of the color scale the axis is placed, and thus also its orientation. @@ -338,26 +324,6 @@ void QCPColorScale::setRangeDrag(bool enabled) mAxisRect.data()->setRangeDrag(0); } -/*! - Sets whether the user can zoom the data range (\ref setDataRange) by scrolling the mouse wheel. - - Note that \ref QCP::iRangeZoom must be in the QCustomPlot's interactions (\ref - QCustomPlot::setInteractions) to allow range dragging. -*/ -void QCPColorScale::setRangeZoom(bool enabled) -{ - if (!mAxisRect) - { - qDebug() << Q_FUNC_INFO << "internal axis rect was deleted"; - return; - } - - if (enabled) - mAxisRect.data()->setRangeZoom(QCPAxis::orientation(mType)); - else - mAxisRect.data()->setRangeZoom(0); -} - /* inherits documentation from base class */ void QCPColorScale::update(UpdatePhase phase) { diff --git a/src/layoutelements/layoutelement-colorscale.h b/src/layoutelements/layoutelement-colorscale.h index 3da4a1c4..1cb17019 100644 --- a/src/layoutelements/layoutelement-colorscale.h +++ b/src/layoutelements/layoutelement-colorscale.h @@ -73,7 +73,6 @@ class QCP_LIB_DECL QCPColorScale : public QCPLayoutElement Q_PROPERTY(QString label READ label WRITE setLabel) Q_PROPERTY(int barWidth READ barWidth WRITE setBarWidth) Q_PROPERTY(bool rangeDrag READ rangeDrag WRITE setRangeDrag) - Q_PROPERTY(bool rangeZoom READ rangeZoom WRITE setRangeZoom) /// \endcond public: explicit QCPColorScale(QCustomPlot *parentPlot); @@ -88,7 +87,6 @@ public: QString label() const; int barWidth () const { return mBarWidth; } bool rangeDrag() const; - bool rangeZoom() const; // setters: void setType(QCPAxis::AxisType type); -- GitLab From 21c6082738873efbc2c981b0832dbd3dd5a32db2 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 12 Mar 2014 10:44:54 +0100 Subject: [PATCH 03/10] Zoom range interaction can now work on many axis --- src/core.cpp | 29 +++++---- src/interactions/interaction-zoomrange.cpp | 71 +++++++--------------- src/interactions/interaction-zoomrange.h | 23 +++---- 3 files changed, 43 insertions(+), 80 deletions(-) diff --git a/src/core.cpp b/src/core.cpp index 79147032..fe4a8538 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -778,20 +778,19 @@ void QCustomPlot::setAutoAddPlottableToLegend(bool on) */ void QCustomPlot::setInteractions(const QCP::Interactions &interactions) { - //mInteractions = interactions; - - foreach(QCPAbstractInteraction *interaction, mInteractions) - { - delete interaction; - } - mInteractions.clear(); + foreach(QCPAbstractInteraction *interaction, mInteractions) + { + delete interaction; + } + mInteractions.clear(); - if(interactions.testFlag(QCP::iRangeZoom)) - { - QCPInteractionZoomRange *interaction = new QCPInteractionZoomRange(this); - interaction->setAxes(xAxis, yAxis); - mInteractions << interaction; - } + if(interactions.testFlag(QCP::iRangeZoom)) + { + QCPInteractionZoomRange *interaction = new QCPInteractionZoomRange(this); + interaction->addAxis(xAxis); + interaction->addAxis(yAxis); + mInteractions << interaction; + } } /*! @@ -2208,8 +2207,7 @@ void QCustomPlot::resizeEvent(QResizeEvent *event) void QCustomPlot::mouseDoubleClickEvent(QMouseEvent *event) { emit mouseDoubleClick(event); - - /* + QVariant details; QCPLayerable *clickedLayerable = layerableAt(event->pos(), false, &details); @@ -2227,6 +2225,7 @@ void QCustomPlot::mouseDoubleClickEvent(QMouseEvent *event) else if (QCPPlotTitle *pt = qobject_cast(clickedLayerable)) emit titleDoubleClick(event, pt); + /* // call double click event of affected layout element: if (QCPLayoutElement *el = layoutElementAt(event->pos())) el->mouseDoubleClickEvent(event); diff --git a/src/interactions/interaction-zoomrange.cpp b/src/interactions/interaction-zoomrange.cpp index 9f191b49..c843cc3f 100644 --- a/src/interactions/interaction-zoomrange.cpp +++ b/src/interactions/interaction-zoomrange.cpp @@ -100,12 +100,8 @@ QCPInteractionZoomRange::QCPInteractionZoomRange(QCustomPlot *parentPlot) : QCPAbstractInteraction(parentPlot), mButtonZoomIn(mbWheelUp), mButtonZoomOut(mbWheelDown), - mOrientations(Qt::Horizontal|Qt::Vertical), - mFactorHorz(0.85), - mFactorVert(0.85), mMousePressPos(), - mAxisHorz(), - mAxisVert() + mAxis() { } @@ -113,39 +109,6 @@ QCPInteractionZoomRange::~QCPInteractionZoomRange() { } -/*! - Returns the range zoom axis of the \a orientation provided. - - \see setRangeZoomAxes -*/ -QCPAxis *QCPInteractionZoomRange::rangeZoomAxis(Qt::Orientation orientation) -{ - return orientation == Qt::Horizontal ? mAxisHorz : mAxisVert; -} - -/*! - Returns the range zoom factor of the \a orientation provided. - - \see setRangeZoomFactor -*/ -double QCPInteractionZoomRange::rangeZoomFactor(Qt::Orientation orientation) const -{ - return orientation == Qt::Horizontal ? mFactorHorz : mFactorVert; -} - -/*! - Sets the axes whose range will be zoomed when \ref setRangeZoom enables mouse wheel zooming on the - QCustomPlot widget. The two axes can be zoomed with different strengths, when different factors - are passed to \ref setRangeZoomFactor(double horizontalFactor, double verticalFactor). - - \see setRangeDragAxes -*/ -void QCPInteractionZoomRange::setAxes(QCPAxis *horizontal, QCPAxis *vertical) -{ - mAxisHorz = horizontal; - mAxisVert = vertical; -} - bool QCPInteractionZoomRange::mousePressEvent(QMouseEvent *event) { MouseButton button = toMouseButton(event->button()); @@ -199,20 +162,30 @@ bool QCPInteractionZoomRange::mouseWheelEvent(QWheelEvent *event) bool QCPInteractionZoomRange::doZoom(const QPoint &pos, double steps) { - bool scale = false; - if (!mAxisHorz.isNull() && mOrientations.testFlag(Qt::Horizontal)) - { - mAxisHorz->scaleRange(pow(mFactorHorz, steps), mAxisHorz->pixelToCoord(pos.x())); - scale = true; - } - if (!mAxisVert.isNull() && mOrientations.testFlag(Qt::Vertical)) + for(int i=0 ; iscaleRange(pow(mFactorVert, steps), mAxisVert->pixelToCoord(pos.y())); - scale = true; + QPointer axis = mAxis[i].first; + int mousePos; + + if(axis->axisType() == QCPAxis::atLeft || axis->axisType() == QCPAxis::atRight) + { + // vertical axis, take the y position of the mouse + mousePos = pos.y(); + } + else + { + // horizontal axis, take the x position of the mouse + mousePos = pos.x(); + } + + axis->scaleRange(pow(mAxis[i].second, steps), axis->pixelToCoord(mousePos)); } - if(scale) + if(mAxis.count()) + { parentPlot()->replot(); + return true; + } - return scale; + return false; } diff --git a/src/interactions/interaction-zoomrange.h b/src/interactions/interaction-zoomrange.h index 04b9c801..37084690 100644 --- a/src/interactions/interaction-zoomrange.h +++ b/src/interactions/interaction-zoomrange.h @@ -37,9 +37,6 @@ class QCP_LIB_DECL QCPInteractionZoomRange : public QCPAbstractInteraction /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(MouseButton buttonZoomIn READ buttonZoomIn WRITE setButtonZoomIn) Q_PROPERTY(MouseButton buttonZoomOut READ buttonZoomOut WRITE setButtonZoomOut) - Q_PROPERTY(Qt::Orientations orientations READ orientations WRITE setOrientations) - Q_PROPERTY(double factorHorz READ factorHorz WRITE setFactorHorz) - Q_PROPERTY(double factorVert READ factorVert WRITE setFactorVert) /// \endcond public: QCPInteractionZoomRange(QCustomPlot *parentPlot); @@ -48,20 +45,16 @@ public: // getters: MouseButton buttonZoomIn() const { return mButtonZoomIn; } MouseButton buttonZoomOut() const { return mButtonZoomOut; } - Qt::Orientations orientations() const { return mOrientations; } - double factorHorz() const { return mFactorHorz; } - double factorVert() const { return mFactorVert; } - QCPAxis *rangeZoomAxis(Qt::Orientation orientation); - double rangeZoomFactor(Qt::Orientation orientation) const; + int axisCount() const { return mAxis.count(); } + QCPAxis *axis(int index) const { return mAxis[index].first; } + double factor(int index) const { return mAxis[index].second; } // setters: void setButtonZoomIn(MouseButton button) { mButtonZoomIn = button; } void setButtonZoomOut(MouseButton button) { mButtonZoomOut = button; } - void setOrientations(Qt::Orientations orientations) { mOrientations = orientations; } - void setFactorHorz(double factor) { mFactorHorz = factor; } - void setFactorVert(double factor) { mFactorVert = factor; } - void setFactor(double factor) { setFactorHorz(factor); setFactorVert(factor); } - void setAxes(QCPAxis *horizontal, QCPAxis *vertical); + void setFactor(double factor); + void clearAxis() { mAxis.clear(); } + void addAxis(QCPAxis *axis, double factor=0.85) { mAxis << qMakePair(QPointer(axis), factor); } // reimplemented virtual method: virtual bool mousePressEvent(QMouseEvent *event); @@ -72,9 +65,7 @@ protected: // property members MouseButton mButtonZoomIn; MouseButton mButtonZoomOut; - Qt::Orientations mOrientations; - double mFactorHorz, mFactorVert; - QPointer mAxisHorz, mAxisVert; + QList, double> > mAxis; // non-property members QPoint mMousePressPos; -- GitLab From 8c9cf9c714046b7f6be20711c563d807da142d9b Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 12 Mar 2014 11:39:01 +0100 Subject: [PATCH 04/10] Reimplementation of the rect zoom with the new API --- src/core.cpp | 20 ++- src/core.h | 3 +- src/global.h | 2 +- src/interactions/interaction-zoomrange.cpp | 45 ++++--- src/interactions/interaction-zoomrect.cpp | 116 ++++++++++++++++++ src/interactions/interaction-zoomrect.h | 73 +++++++++++ src/layoutelements/layoutelement-axisrect.cpp | 31 ----- 7 files changed, 238 insertions(+), 52 deletions(-) create mode 100644 src/interactions/interaction-zoomrect.cpp create mode 100644 src/interactions/interaction-zoomrect.h diff --git a/src/core.cpp b/src/core.cpp index fe4a8538..a8ae8086 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -38,6 +38,7 @@ #include "item.h" #include "interaction.h" #include "interactions/interaction-zoomrange.h" +#include "interactions/interaction-zoomrect.h" /*! \mainpage %QCustomPlot 1.2.0-beta Documentation @@ -722,6 +723,16 @@ void QCustomPlot::setAutoAddPlottableToLegend(bool on) mAutoAddPlottableToLegend = on; } +QCP::Interactions QCustomPlot::interactions() const +{ + return 0; +} + +QCPAbstractInteraction *QCustomPlot::interaction(QCP::Interaction) const +{ + return NULL; +} + /*! Sets the possible interactions of this QCustomPlot as an or-combination of \ref QCP::Interaction enums. There are the following types of interactions: @@ -791,6 +802,13 @@ void QCustomPlot::setInteractions(const QCP::Interactions &interactions) interaction->addAxis(yAxis); mInteractions << interaction; } + if(interactions.testFlag(QCP::iRectZoom)) + { + QCPInteractionZoomRect *interaction = new QCPInteractionZoomRect(this); + interaction->addAxis(xAxis); + interaction->addAxis(yAxis); + mInteractions << interaction; + } } /*! @@ -2249,8 +2267,6 @@ void QCustomPlot::mouseDoubleClickEvent(QMouseEvent *event) */ void QCustomPlot::mousePressEvent(QMouseEvent *event) { - qDebug("coucou"); - emit mousePress(event); /* diff --git a/src/core.h b/src/core.h index c64f2b9c..9d2eabb8 100644 --- a/src/core.h +++ b/src/core.h @@ -87,7 +87,8 @@ public: QCP::AntialiasedElements antialiasedElements() const { return mAntialiasedElements; } QCP::AntialiasedElements notAntialiasedElements() const { return mNotAntialiasedElements; } bool autoAddPlottableToLegend() const { return mAutoAddPlottableToLegend; } - const QCP::Interactions interactions() const { return 0; } + QCP::Interactions interactions() const; + QCPAbstractInteraction *interaction(QCP::Interaction) const; int selectionTolerance() const { return mSelectionTolerance; } bool noAntialiasingOnDrag() const { return mNoAntialiasingOnDrag; } QCP::PlottingHints plottingHints() const { return mPlottingHints; } diff --git a/src/global.h b/src/global.h index 9bbb4f8a..8187cf03 100644 --- a/src/global.h +++ b/src/global.h @@ -139,7 +139,7 @@ enum Interaction { iRangeDrag = 0x001 ///< 0x001 Axis ranges ar ,iSelectLegend = 0x020 ///< 0x020 Legends are selectable (or their child items, see QCPLegend::setSelectableParts) ,iSelectItems = 0x040 ///< 0x040 Items are selectable (Rectangles, Arrows, Textitems, etc. see \ref QCPAbstractItem) ,iSelectOther = 0x080 ///< 0x080 All other objects are selectable (e.g. your own derived layerables, the plot title,...) - ,iZoomRect = 0x100 ///< 0x100 Acis ranges are zoomable by drawing a rectangle on a zone (see \ref QCPAxisRect::setRangeZoom, \ref QCPAxisRect::setRangeZoomAxes) + ,iRectZoom = 0x100 ///< 0x100 Axis ranges are zoomable by drawing a rectangle on a zone (see \ref QCPAxisRect::setRangeZoom, \ref QCPAxisRect::setRangeZoomAxes) }; Q_DECLARE_FLAGS(Interactions, Interaction) diff --git a/src/interactions/interaction-zoomrange.cpp b/src/interactions/interaction-zoomrange.cpp index c843cc3f..ea2d293c 100644 --- a/src/interactions/interaction-zoomrange.cpp +++ b/src/interactions/interaction-zoomrange.cpp @@ -109,6 +109,15 @@ QCPInteractionZoomRange::~QCPInteractionZoomRange() { } +void QCPInteractionZoomRange::setFactor(double factor) +{ + QMutableListIterator, double> > iterator(mAxis); + while(iterator.hasNext()) + { + iterator.next().second = factor; + } +} + bool QCPInteractionZoomRange::mousePressEvent(QMouseEvent *event) { MouseButton button = toMouseButton(event->button()); @@ -162,30 +171,32 @@ bool QCPInteractionZoomRange::mouseWheelEvent(QWheelEvent *event) bool QCPInteractionZoomRange::doZoom(const QPoint &pos, double steps) { + bool scaled = false; for(int i=0 ; i axis = mAxis[i].first; - int mousePos; - - if(axis->axisType() == QCPAxis::atLeft || axis->axisType() == QCPAxis::atRight) + if(not axis.isNull()) { - // vertical axis, take the y position of the mouse - mousePos = pos.y(); + int mousePos; + + if(axis->axisType() == QCPAxis::atLeft || axis->axisType() == QCPAxis::atRight) + { + // vertical axis, take the y position of the mouse + mousePos = pos.y(); + } + else + { + // horizontal axis, take the x position of the mouse + mousePos = pos.x(); + } + + axis->scaleRange(pow(mAxis[i].second, steps), axis->pixelToCoord(mousePos)); + scaled = true; } - else - { - // horizontal axis, take the x position of the mouse - mousePos = pos.x(); - } - - axis->scaleRange(pow(mAxis[i].second, steps), axis->pixelToCoord(mousePos)); } - if(mAxis.count()) - { + if(scaled) parentPlot()->replot(); - return true; - } - return false; + return scaled; } diff --git a/src/interactions/interaction-zoomrect.cpp b/src/interactions/interaction-zoomrect.cpp new file mode 100644 index 00000000..0b9ecf3d --- /dev/null +++ b/src/interactions/interaction-zoomrect.cpp @@ -0,0 +1,116 @@ +/*************************************************************************** +** ** +** QCustomPlot, an easy to use, modern plotting widget for Qt ** +** Copyright (C) 2011, 2012, 2013, 2014 Emanuel Eichhammer ** +** ** +** This program is free software: you can redistribute it and/or modify ** +** it under the terms of the GNU General Public License as published by ** +** the Free Software Foundation, either version 3 of the License, or ** +** (at your option) any later version. ** +** ** +** This program is distributed in the hope that it will be useful, ** +** but WITHOUT ANY WARRANTY; without even the implied warranty of ** +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** +** GNU General Public License for more details. ** +** ** +** You should have received a copy of the GNU General Public License ** +** along with this program. If not, see http://www.gnu.org/licenses/. ** +** ** +**************************************************************************** +** Author: Erwan Mathieu ** +** Website/Contact: http://www.qcustomplot.com/ ** +** Date: 12.03.14 ** +** Version: 1.2.0-beta ** +****************************************************************************/ + +#include "interaction-zoomrect.h" + +#include "axis.h" +#include "core.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////// QCPInteractionZoomRect +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*! \class QCPInteractionZoomRect + \brief +*/ + +/* start documentation of inline functions */ + + +/* end documentation of inline functions */ + +QCPInteractionZoomRect::QCPInteractionZoomRect(QCustomPlot *parentPlot) : + QCPAbstractInteraction(parentPlot), + mButtonZoom(mbLeft), + mMousePressPos(), + mAxis(), + mRubberBand(new QRubberBand(QRubberBand::Rectangle, parentPlot)) +{ + mRubberBand->hide(); +} + +QCPInteractionZoomRect::~QCPInteractionZoomRect() +{ +} + +bool QCPInteractionZoomRect::mousePressEvent(QMouseEvent *event) +{ + if(toMouseButton(event->button()) == mButtonZoom && not mAxis.isEmpty()) + { + mMousePressPos = event->pos(); + mRubberBand->setGeometry(QRect(mMousePressPos, QSize(0, 0))); + mRubberBand->show(); + } + + return false; +} + +bool QCPInteractionZoomRect::mouseMoveEvent(QMouseEvent *event) +{ + if(mRubberBand->isVisible()) + mRubberBand->setGeometry(QRect(mMousePressPos, event->pos()).normalized()); +} + +bool QCPInteractionZoomRect::mouseReleaseEvent(QMouseEvent *event) +{ + bool ranged = false; + if(toMouseButton(event->button()) == mButtonZoom && mRubberBand->isVisible()) + { + mRubberBand->hide(); + QRect rect = mRubberBand->geometry(); + if(rect.width() > 10 && rect.height() > 10) // protection against unvolotary moves + { + foreach(QPointer axis, mAxis) + { + if(not axis.isNull()) + { + double lower; + double upper; + + if(axis->axisType() == QCPAxis::atLeft || axis->axisType() == QCPAxis::atRight) + { + // vertical axis, take the rect height + lower = axis->pixelToCoord(rect.bottom()); + upper = axis->pixelToCoord(rect.top()); + } + else + { + // horizontal axis, take the rect width + lower = axis->pixelToCoord(rect.left()); + upper = axis->pixelToCoord(rect.right()); + } + + axis->setRange(lower, upper); + ranged = true; + } + } + } + } + + if(ranged) + mParentPlot->replot(); + + return ranged; +} diff --git a/src/interactions/interaction-zoomrect.h b/src/interactions/interaction-zoomrect.h new file mode 100644 index 00000000..da4391fd --- /dev/null +++ b/src/interactions/interaction-zoomrect.h @@ -0,0 +1,73 @@ +/*************************************************************************** +** ** +** QCustomPlot, an easy to use, modern plotting widget for Qt ** +** Copyright (C) 2011, 2012, 2013, 2014 Emanuel Eichhammer ** +** ** +** This program is free software: you can redistribute it and/or modify ** +** it under the terms of the GNU General Public License as published by ** +** the Free Software Foundation, either version 3 of the License, or ** +** (at your option) any later version. ** +** ** +** This program is distributed in the hope that it will be useful, ** +** but WITHOUT ANY WARRANTY; without even the implied warranty of ** +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** +** GNU General Public License for more details. ** +** ** +** You should have received a copy of the GNU General Public License ** +** along with this program. If not, see http://www.gnu.org/licenses/. ** +** ** +**************************************************************************** +** Author: Erwan Mathieu ** +** Website/Contact: http://www.qcustomplot.com/ ** +** Date: 12.03.14 ** +** Version: 1.2.0-beta ** +****************************************************************************/ + +#ifndef QCP_INTERACTION_ZOOMRECT_H +#define QCP_INTERACTION_ZOOMRECT_H + +#include "interaction.h" + +class QRubberBand; +class QCPAxis; + + +class QCP_LIB_DECL QCPInteractionZoomRect : public QCPAbstractInteraction +{ + Q_OBJECT + /// \cond INCLUDE_QPROPERTIES + Q_PROPERTY(MouseButton buttonZoom READ buttonZoom WRITE setButtonZoom) + /// \endcond +public: + QCPInteractionZoomRect(QCustomPlot *parentPlot); + virtual ~QCPInteractionZoomRect(); + + // getters: + MouseButton buttonZoom() const { return mButtonZoom; } + int axisCount() const { return mAxis.count(); } + QCPAxis *axis(int index) const { return mAxis[index]; } + + // setters: + void setButtonZoom(MouseButton button) { mButtonZoom = button; } + void clearAxis() { mAxis.clear(); } + void addAxis(QCPAxis *axis) { mAxis << axis; } + + // reimplemented virtual method: + virtual bool mousePressEvent(QMouseEvent *event); + virtual bool mouseMoveEvent(QMouseEvent *event); + virtual bool mouseReleaseEvent(QMouseEvent *event); + +protected: + // property members + MouseButton mButtonZoom; + QList > mAxis; + + // non-property members + QPoint mMousePressPos; + QRubberBand *mRubberBand; + +private: + Q_DISABLE_COPY(QCPInteractionZoomRect) +}; + +#endif // QCP_INTERACTION_ZOOMRECT_H diff --git a/src/layoutelements/layoutelement-axisrect.cpp b/src/layoutelements/layoutelement-axisrect.cpp index 1510e6c9..79f34f12 100644 --- a/src/layoutelements/layoutelement-axisrect.cpp +++ b/src/layoutelements/layoutelement-axisrect.cpp @@ -811,11 +811,6 @@ void QCPAxisRect::mousePressEvent(QMouseEvent *event) if (mRangeDragVertAxis) mDragStartVertRange = mRangeDragVertAxis.data()->range(); } - else if (mParentPlot->interactions().testFlag(QCP::iZoomRect)) - { - mZoomRubber->setGeometry(QRect(mDragStart, QSize(0, 0))); - mZoomRubber->show(); - } } } @@ -870,10 +865,6 @@ void QCPAxisRect::mouseMoveEvent(QMouseEvent *event) mParentPlot->replot(); } } - else if (mParentPlot->interactions().testFlag(QCP::iZoomRect)) - { - mZoomRubber->setGeometry(QRect(mDragStart, event->pos()).normalized()); - } } } @@ -887,26 +878,4 @@ void QCPAxisRect::mouseReleaseEvent(QMouseEvent *event) mParentPlot->setAntialiasedElements(mAADragBackup); mParentPlot->setNotAntialiasedElements(mNotAADragBackup); } - - if (event->button() == Qt::LeftButton && mParentPlot->interactions().testFlag(QCP::iZoomRect)) - { - mZoomRubber->hide(); - QRect rect = mZoomRubber->geometry(); - if(rect.width() > 10 && rect.height() > 10) // protection against unvolotary moves - { - if (QCPAxis *rangeDragHorzAxis = mRangeDragHorzAxis.data()) - { - double left = rangeDragHorzAxis->pixelToCoord(rect.left()); - double right = rangeDragHorzAxis->pixelToCoord(rect.right()); - rangeDragHorzAxis->setRange(left, right); - } - if (QCPAxis *rangeDragVertAxis = mRangeDragVertAxis.data()) - { - double top = rangeDragVertAxis->pixelToCoord(rect.top()); - double bottom = rangeDragVertAxis->pixelToCoord(rect.bottom()); - rangeDragVertAxis->setRange(bottom, top); - } - mParentPlot->replot(); - } - } } -- GitLab From 6cd8a51dbb42d491e2794fb61163cc9b27c333d9 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 12 Mar 2014 17:41:30 +0100 Subject: [PATCH 05/10] Reimplementation of the select mechanism with the new API, polishing --- src/core.cpp | 225 +++++++++--------- src/core.h | 10 +- src/global.h | 1 - src/interaction.cpp | 30 --- src/interaction.h | 10 +- src/interactions/interaction-dragrange.cpp | 156 ++++++++++++ src/interactions/interaction-dragrange.h | 77 ++++++ src/interactions/interaction-select.cpp | 124 ++++++++++ src/interactions/interaction-select.h | 73 ++++++ src/interactions/interaction-zoomrange.cpp | 24 +- src/interactions/interaction-zoomrange.h | 9 +- src/interactions/interaction-zoomrect.cpp | 20 +- src/interactions/interaction-zoomrect.h | 14 +- src/layer.h | 8 +- src/layoutelements/layoutelement-axisrect.cpp | 152 +----------- src/layoutelements/layoutelement-axisrect.h | 16 -- .../layoutelement-colorscale.cpp | 36 --- src/layoutelements/layoutelement-colorscale.h | 4 - 18 files changed, 582 insertions(+), 407 deletions(-) create mode 100644 src/interactions/interaction-dragrange.cpp create mode 100644 src/interactions/interaction-dragrange.h create mode 100644 src/interactions/interaction-select.cpp create mode 100644 src/interactions/interaction-select.h diff --git a/src/core.cpp b/src/core.cpp index a8ae8086..7fa7be08 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -39,6 +39,8 @@ #include "interaction.h" #include "interactions/interaction-zoomrange.h" #include "interactions/interaction-zoomrect.h" +#include "interactions/interaction-dragrange.h" +#include "interactions/interaction-select.h" /*! \mainpage %QCustomPlot 1.2.0-beta Documentation @@ -546,13 +548,11 @@ QCustomPlot::QCustomPlot(QWidget *parent) : mNotAntialiasedElements(QCP::aeNone), mInteractions(), mSelectionTolerance(8), - mNoAntialiasingOnDrag(false), mBackgroundBrush(Qt::white, Qt::SolidPattern), mBackgroundScaled(true), mBackgroundScaledMode(Qt::KeepAspectRatioByExpanding), mCurrentLayer(0), mPlottingHints(QCP::phCacheLabels|QCP::phForceRepaint), - mMultiSelectModifier(Qt::ControlModifier), mPaintBuffer(size()), mMouseEventElement(0), mReplotting(false) @@ -725,12 +725,60 @@ void QCustomPlot::setAutoAddPlottableToLegend(bool on) QCP::Interactions QCustomPlot::interactions() const { - return 0; + QCP::Interactions result = 0; + + if(interaction(QCP::iRangeDrag)) + result |= QCP::iRangeDrag; + if(interaction(QCP::iRangeZoom)) + result |= QCP::iRangeZoom; + if(interaction(QCP::iRectZoom)) + result |= QCP::iRectZoom; + if(QCPInteractionSelect *select = qobject_cast(interaction(QCP::iMultiSelect))) + result |= select->interactions(); + + return result; } -QCPAbstractInteraction *QCustomPlot::interaction(QCP::Interaction) const +QCPAbstractInteraction *QCustomPlot::interaction(QCP::Interaction interaction) const { - return NULL; + switch(interaction) + { + case QCP::iRangeDrag: + foreach(QCPAbstractInteraction *interaction, mInteractions) + { + if(qobject_cast(interaction)) + return interaction; + } + break; + case QCP::iRangeZoom: + foreach(QCPAbstractInteraction *interaction, mInteractions) + { + if(qobject_cast(interaction)) + return interaction; + } + break; + case QCP::iRectZoom: + foreach(QCPAbstractInteraction *interaction, mInteractions) + { + if(qobject_cast(interaction)) + return interaction; + } + break; + case QCP::iMultiSelect: + case QCP::iSelectPlottables: + case QCP::iSelectAxes: + case QCP::iSelectLegend: + case QCP::iSelectItems: + case QCP::iSelectOther: + foreach(QCPAbstractInteraction *interaction, mInteractions) + { + if(qobject_cast(interaction)) + return interaction; + } + break; + } + + return 0; } /*! @@ -789,26 +837,64 @@ QCPAbstractInteraction *QCustomPlot::interaction(QCP::Interaction) const */ void QCustomPlot::setInteractions(const QCP::Interactions &interactions) { - foreach(QCPAbstractInteraction *interaction, mInteractions) + QCPAbstractInteraction *interactionZoomRange = interaction(QCP::iRangeZoom); + if(interactions.testFlag(QCP::iRangeZoom) && !interactionZoomRange) { - delete interaction; + QCPInteractionZoomRange *interaction = new QCPInteractionZoomRange(this); + interaction->addAxis(xAxis); + interaction->addAxis(yAxis); + mInteractions << interaction; + } + else if(not interactions.testFlag(QCP::iRangeZoom) && interactionZoomRange) + { + delete interactionZoomRange; + mInteractions.removeAll(interactionZoomRange); } - mInteractions.clear(); - if(interactions.testFlag(QCP::iRangeZoom)) + QCPAbstractInteraction *interactionRectZoom = interaction(QCP::iRectZoom); + if(interactions.testFlag(QCP::iRectZoom) && !interactionRectZoom) { - QCPInteractionZoomRange *interaction = new QCPInteractionZoomRange(this); + QCPInteractionZoomRect *interaction = new QCPInteractionZoomRect(this); interaction->addAxis(xAxis); interaction->addAxis(yAxis); mInteractions << interaction; } - if(interactions.testFlag(QCP::iRectZoom)) + else if(not interactions.testFlag(QCP::iRectZoom) && interactionRectZoom) { - QCPInteractionZoomRect *interaction = new QCPInteractionZoomRect(this); + delete interactionRectZoom; + mInteractions.removeAll(interactionRectZoom); + } + + QCPAbstractInteraction *interactionRangeDrag = interaction(QCP::iRangeDrag); + if(interactions.testFlag(QCP::iRangeDrag) && !interactionRangeDrag) + { + QCPInteractionDragRange *interaction = new QCPInteractionDragRange(this); interaction->addAxis(xAxis); interaction->addAxis(yAxis); mInteractions << interaction; } + else if(!interactions.testFlag(QCP::iRangeDrag) && interactionRangeDrag) + { + delete interactionRangeDrag; + mInteractions.removeAll(interactionRangeDrag); + } + + QCPInteractionSelect *interactionSelect = qobject_cast(interaction(QCP::iMultiSelect)); + QCP::Interactions interactionsSelectFlag = interactions & (QCP::iMultiSelect | QCP::iSelectPlottables | QCP::iSelectAxes | QCP::iSelectLegend | QCP::iSelectItems | QCP::iSelectOther); + if(interactionsSelectFlag) + { + if(!interactionSelect) + { + interactionSelect = new QCPInteractionSelect(this); + mInteractions << interactionSelect; + } + interactionSelect->setInteractions(interactionsSelectFlag); + } + else if(interactionSelect) + { + delete interactionSelect; + mInteractions.removeAll(interactionSelect); + } } /*! @@ -820,10 +906,13 @@ void QCustomPlot::setInteractions(const QCP::Interactions &interactions) */ void QCustomPlot::setInteraction(const QCP::Interaction &interaction, bool enabled) { - /*if (!enabled && mInteractions.testFlag(interaction)) - mInteractions &= ~interaction; - else if (enabled && !mInteractions.testFlag(interaction)) - mInteractions |= interaction;*/ + QCP::Interactions currentInteractions = interactions(); + if(enabled) + currentInteractions |= interaction; + else + currentInteractions &= ~interaction; + + setInteractions(currentInteractions); } void QCustomPlot::addInteraction(QCPAbstractInteraction *interaction) @@ -849,20 +938,6 @@ void QCustomPlot::setSelectionTolerance(int pixels) mSelectionTolerance = pixels; } -/*! - Sets whether antialiasing is disabled for this QCustomPlot while the user is dragging axes - ranges. If many objects, especially plottables, are drawn antialiased, this greatly improves - performance during dragging. Thus it creates a more responsive user experience. As soon as the - user stops dragging, the last replot is done with normal antialiasing, to restore high image - quality. - - \see setAntialiasedElements, setNotAntialiasedElements -*/ -void QCustomPlot::setNoAntialiasingOnDrag(bool enabled) -{ - mNoAntialiasingOnDrag = enabled; -} - /*! Sets the plotting hints for this QCustomPlot instance as an \a or combination of QCP::PlottingHint. @@ -890,21 +965,6 @@ void QCustomPlot::setPlottingHint(QCP::PlottingHint hint, bool enabled) setPlottingHints(newHints); } -/*! - Sets the keyboard modifier that will be recognized as multi-select-modifier. - - If \ref QCP::iMultiSelect is specified in \ref setInteractions, the user may select multiple objects - by clicking on them one after the other while holding down \a modifier. - - By default the multi-select-modifier is set to Qt::ControlModifier. - - \see setInteractions -*/ -void QCustomPlot::setMultiSelectModifier(Qt::KeyboardModifier modifier) -{ - mMultiSelectModifier = modifier; -} - /*! Sets the viewport of this QCustomPlot. The Viewport is the area that the top level layout (QCustomPlot::plotLayout()) uses as its rect. Normally, the viewport is the entire widget rect. @@ -2243,7 +2303,6 @@ void QCustomPlot::mouseDoubleClickEvent(QMouseEvent *event) else if (QCPPlotTitle *pt = qobject_cast(clickedLayerable)) emit titleDoubleClick(event, pt); - /* // call double click event of affected layout element: if (QCPLayoutElement *el = layoutElementAt(event->pos())) el->mouseDoubleClickEvent(event); @@ -2253,7 +2312,7 @@ void QCustomPlot::mouseDoubleClickEvent(QMouseEvent *event) { mMouseEventElement->mouseReleaseEvent(event); mMouseEventElement = 0; - }*/ + } //QWidget::mouseDoubleClickEvent(event); don't call base class implementation because it would just cause a mousePress/ReleaseEvent, which we don't want. } @@ -2269,22 +2328,16 @@ void QCustomPlot::mousePressEvent(QMouseEvent *event) { emit mousePress(event); - /* mMousePressPos = event->pos(); // need this to determine in releaseEvent whether it was a click (no position change between press and release) // call event of affected layout element: mMouseEventElement = layoutElementAt(event->pos()); if (mMouseEventElement) mMouseEventElement->mousePressEvent(event); - */ foreach(QCPAbstractInteraction *interaction, mInteractions) { - if(interaction->mousePressEvent(event)) - { - event->accept(); - break; - } + interaction->mousePressEvent(event); } QWidget::mousePressEvent(event); @@ -2303,19 +2356,13 @@ void QCustomPlot::mouseMoveEvent(QMouseEvent *event) { emit mouseMove(event); - /* // call event of affected layout element: if (mMouseEventElement) mMouseEventElement->mouseMoveEvent(event); - */ foreach(QCPAbstractInteraction *interaction, mInteractions) { - if(interaction->mouseMoveEvent(event)) - { - event->accept(); - break; - } + interaction->mouseMoveEvent(event); } QWidget::mouseMoveEvent(event); @@ -2337,46 +2384,10 @@ void QCustomPlot::mouseMoveEvent(QMouseEvent *event) */ void QCustomPlot::mouseReleaseEvent(QMouseEvent *event) { - /*emit mouseRelease(event); - bool doReplot = false; + emit mouseRelease(event); if ((mMousePressPos-event->pos()).manhattanLength() < 5) // determine whether it was a click operation { - if (event->button() == Qt::LeftButton) - { - // handle selection mechanism: - QVariant details; - QCPLayerable *clickedLayerable = layerableAt(event->pos(), true, &details); - bool selectionStateChanged = false; - bool additive = mInteractions.testFlag(QCP::iMultiSelect) && event->modifiers().testFlag(mMultiSelectModifier); - // deselect all other layerables if not additive selection: - if (!additive) - { - foreach (QCPLayer *layer, mLayers) - { - foreach (QCPLayerable *layerable, layer->children()) - { - if (layerable != clickedLayerable && mInteractions.testFlag(layerable->selectionCategory())) - { - bool selChanged = false; - layerable->deselectEvent(&selChanged); - selectionStateChanged |= selChanged; - } - } - } - } - if (clickedLayerable && mInteractions.testFlag(clickedLayerable->selectionCategory())) - { - // a layerable was actually clicked, call its selectEvent: - bool selChanged = false; - clickedLayerable->selectEvent(event, additive, details, &selChanged); - selectionStateChanged |= selChanged; - } - doReplot = true; - if (selectionStateChanged) - emit selectionChangedByUser(); - } - // emit specialized object click signals: QVariant details; QCPLayerable *clickedLayerable = layerableAt(event->pos(), false, &details); // for these signals, selectability is ignored, that's why we call this again with onlySelectable set to false @@ -2401,16 +2412,9 @@ void QCustomPlot::mouseReleaseEvent(QMouseEvent *event) mMouseEventElement = 0; } - if (doReplot || noAntialiasingOnDrag()) - replot();*/ - foreach(QCPAbstractInteraction *interaction, mInteractions) { - if(interaction->mouseReleaseEvent(event)) - { - event->accept(); - break; - } + interaction->mouseReleaseEvent(event); } QWidget::mouseReleaseEvent(event); @@ -2425,19 +2429,14 @@ void QCustomPlot::mouseReleaseEvent(QMouseEvent *event) void QCustomPlot::wheelEvent(QWheelEvent *event) { emit mouseWheel(event); - /* + // call event of affected layout element: if (QCPLayoutElement *el = layoutElementAt(event->pos())) el->wheelEvent(event); - */ foreach(QCPAbstractInteraction *interaction, mInteractions) { - if(interaction->mouseWheelEvent(event)) - { - event->accept(); - break; - } + interaction->mouseWheelEvent(event); } QWidget::wheelEvent(event); diff --git a/src/core.h b/src/core.h index 9d2eabb8..53910926 100644 --- a/src/core.h +++ b/src/core.h @@ -51,8 +51,6 @@ class QCP_LIB_DECL QCustomPlot : public QWidget Q_PROPERTY(QCPLayoutGrid* plotLayout READ plotLayout) Q_PROPERTY(bool autoAddPlottableToLegend READ autoAddPlottableToLegend WRITE setAutoAddPlottableToLegend) Q_PROPERTY(int selectionTolerance READ selectionTolerance WRITE setSelectionTolerance) - Q_PROPERTY(bool noAntialiasingOnDrag READ noAntialiasingOnDrag WRITE setNoAntialiasingOnDrag) - Q_PROPERTY(Qt::KeyboardModifier multiSelectModifier READ multiSelectModifier WRITE setMultiSelectModifier) /// \endcond public: /*! @@ -90,9 +88,7 @@ public: QCP::Interactions interactions() const; QCPAbstractInteraction *interaction(QCP::Interaction) const; int selectionTolerance() const { return mSelectionTolerance; } - bool noAntialiasingOnDrag() const { return mNoAntialiasingOnDrag; } QCP::PlottingHints plottingHints() const { return mPlottingHints; } - Qt::KeyboardModifier multiSelectModifier() const { return mMultiSelectModifier; } // setters: void setViewport(const QRect &rect); @@ -110,10 +106,8 @@ public: void setInteraction(const QCP::Interaction &interaction, bool enabled=true); void addInteraction(QCPAbstractInteraction *interaction); void setSelectionTolerance(int pixels); - void setNoAntialiasingOnDrag(bool enabled); void setPlottingHints(const QCP::PlottingHints &hints); void setPlottingHint(QCP::PlottingHint hint, bool enabled=true); - void setMultiSelectModifier(Qt::KeyboardModifier modifier); // non-property methods: // plottable interface: @@ -166,6 +160,7 @@ public: QCPAxisRect* axisRect(int index=0) const; QList axisRects() const; QCPLayoutElement* layoutElementAt(const QPointF &pos) const; + QCPLayerable *layerableAt(const QPointF &pos, bool onlySelectable, QVariant *selectionDetails=0) const; Q_SLOT void rescaleAxes(bool onlyVisiblePlottables=false); QList selectedAxes() const; @@ -218,7 +213,6 @@ protected: QCP::AntialiasedElements mAntialiasedElements, mNotAntialiasedElements; QList mInteractions; int mSelectionTolerance; - bool mNoAntialiasingOnDrag; QBrush mBackgroundBrush; QPixmap mBackgroundPixmap; QPixmap mScaledBackgroundPixmap; @@ -226,7 +220,6 @@ protected: Qt::AspectRatioMode mBackgroundScaledMode; QCPLayer *mCurrentLayer; QCP::PlottingHints mPlottingHints; - Qt::KeyboardModifier mMultiSelectModifier; // non-property members: QPixmap mPaintBuffer; @@ -252,7 +245,6 @@ protected: // non-virtual methods: void updateLayerIndices() const; - QCPLayerable *layerableAt(const QPointF &pos, bool onlySelectable, QVariant *selectionDetails=0) const; void drawBackground(QCPPainter *painter); friend class QCPLegend; diff --git a/src/global.h b/src/global.h index 8187cf03..d7dc46eb 100644 --- a/src/global.h +++ b/src/global.h @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) diff --git a/src/interaction.cpp b/src/interaction.cpp index e8ba7b39..c74f8668 100644 --- a/src/interaction.cpp +++ b/src/interaction.cpp @@ -46,36 +46,6 @@ QCPAbstractInteraction::~QCPAbstractInteraction() { } -bool QCPAbstractInteraction::mouseDoubleClickEvent(QMouseEvent *event) -{ - Q_UNUSED(event) - return false; -} - -bool QCPAbstractInteraction::mousePressEvent(QMouseEvent *event) -{ - Q_UNUSED(event) - return false; -} - -bool QCPAbstractInteraction::mouseMoveEvent(QMouseEvent *event) -{ - Q_UNUSED(event) - return false; -} - -bool QCPAbstractInteraction::mouseReleaseEvent(QMouseEvent *event) -{ - Q_UNUSED(event) - return false; -} - -bool QCPAbstractInteraction::mouseWheelEvent(QWheelEvent *event) -{ - Q_UNUSED(event) - return false; -} - QCPAbstractInteraction::MouseButton QCPAbstractInteraction::toMouseButton(Qt::MouseButton button) { switch(button) diff --git a/src/interaction.h b/src/interaction.h index b4b08904..ccfc2925 100644 --- a/src/interaction.h +++ b/src/interaction.h @@ -61,11 +61,11 @@ public: void setActive(bool active) { mActive = active; } // introduced virtual method: - virtual bool mouseDoubleClickEvent(QMouseEvent *event); - virtual bool mousePressEvent(QMouseEvent *event); - virtual bool mouseMoveEvent(QMouseEvent *event); - virtual bool mouseReleaseEvent(QMouseEvent *event); - virtual bool mouseWheelEvent(QWheelEvent *event); + virtual void mouseDoubleClickEvent(QMouseEvent *event) { Q_UNUSED(event); } + virtual void mousePressEvent(QMouseEvent *event) { Q_UNUSED(event); } + virtual void mouseMoveEvent(QMouseEvent *event) { Q_UNUSED(event); } + virtual void mouseReleaseEvent(QMouseEvent *event) { Q_UNUSED(event); } + virtual void mouseWheelEvent(QWheelEvent *event) { Q_UNUSED(event); } // static methods: MouseButton toMouseButton(Qt::MouseButton button); diff --git a/src/interactions/interaction-dragrange.cpp b/src/interactions/interaction-dragrange.cpp new file mode 100644 index 00000000..c8558d82 --- /dev/null +++ b/src/interactions/interaction-dragrange.cpp @@ -0,0 +1,156 @@ +/*************************************************************************** +** ** +** QCustomPlot, an easy to use, modern plotting widget for Qt ** +** Copyright (C) 2011, 2012, 2013, 2014 Emanuel Eichhammer ** +** ** +** This program is free software: you can redistribute it and/or modify ** +** it under the terms of the GNU General Public License as published by ** +** the Free Software Foundation, either version 3 of the License, or ** +** (at your option) any later version. ** +** ** +** This program is distributed in the hope that it will be useful, ** +** but WITHOUT ANY WARRANTY; without even the implied warranty of ** +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** +** GNU General Public License for more details. ** +** ** +** You should have received a copy of the GNU General Public License ** +** along with this program. If not, see http://www.gnu.org/licenses/. ** +** ** +**************************************************************************** +** Author: Erwan Mathieu ** +** Website/Contact: http://www.qcustomplot.com/ ** +** Date: 12.03.14 ** +** Version: 1.2.0-beta ** +****************************************************************************/ + +#include "interaction-dragrange.h" + +#include "axis.h" +#include "core.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////// QCPInteractionDragRange +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*! \class QCPInteractionDragRange + \brief +*/ + +/* start documentation of inline functions */ + + +/* end documentation of inline functions */ + +QCPInteractionDragRange::QCPInteractionDragRange(QCustomPlot *parentPlot) : + QCPAbstractInteraction(parentPlot), + mButton(mbLeft), + mAxis(), + mNoAntialiasingOnDrag(true), + mMousePressPos(), + mRangesStart() +{ +} + +QCPInteractionDragRange::~QCPInteractionDragRange() +{ +} + +/*! + Sets whether antialiasing is disabled for this QCustomPlot while the user is dragging axes + ranges. If many objects, especially plottables, are drawn antialiased, this greatly improves + performance during dragging. Thus it creates a more responsive user experience. As soon as the + user stops dragging, the last replot is done with normal antialiasing, to restore high image + quality. +*/ +void QCPInteractionDragRange::setNoAntialiasingOnDrag(bool enabled) +{ + mNoAntialiasingOnDrag = enabled; +} + +void QCPInteractionDragRange::mousePressEvent(QMouseEvent *event) +{ + if(toMouseButton(event->button()) == mButton && not mAxis.isEmpty()) + { + mMousePressPos = event->pos(); + + // initialize antialiasing backup in case we start dragging: + if (mNoAntialiasingOnDrag) + { + mAADragBackup = mParentPlot->antialiasedElements(); + mNotAADragBackup = mParentPlot->notAntialiasedElements(); + } + + mRangesStart.clear(); + foreach(QPointer axis, mAxis) + { + if(not axis.isNull()) + { + mRangesStart << axis->range(); + } + } + } +} + +void QCPInteractionDragRange::mouseMoveEvent(QMouseEvent *event) +{ + bool ranged = false; + + if(not mMousePressPos.isNull()) + { + int i=0; + foreach(QPointer axis, mAxis) + { + if(not axis.isNull()) + { + QCPRange rangeStart = mRangesStart[i++]; + int dragStart, mousePos; + if(axis->axisType() == QCPAxis::atLeft || axis->axisType() == QCPAxis::atRight) + { + // vertical axis, take the y position of the mouse + dragStart = mMousePressPos.y(); + mousePos = event->pos().y(); + } + else + { + // horizontal axis, take the x position of the mouse + dragStart = mMousePressPos.x(); + mousePos = event->pos().x(); + } + + if (axis->scaleType() == QCPAxis::stLinear) + { + double diff = axis->pixelToCoord(dragStart) - axis->pixelToCoord(mousePos); + axis->setRange(rangeStart.lower + diff, rangeStart.upper + diff); + ranged = true; + } + else if (axis->scaleType() == QCPAxis::stLogarithmic) + { + double diff = axis->pixelToCoord(dragStart) / axis->pixelToCoord(mousePos); + axis->setRange(rangeStart.lower * diff, rangeStart.upper * diff); + ranged = true; + } + } + } + } + + if(ranged) + { + if (mNoAntialiasingOnDrag) + mParentPlot->setNotAntialiasedElements(QCP::aeAll); + mParentPlot->replot(); + } +} + +void QCPInteractionDragRange::mouseReleaseEvent(QMouseEvent *event) +{ + if(toMouseButton(event->button()) == mButton && not mMousePressPos.isNull()) + { + mMousePressPos = QPoint(); + if (mNoAntialiasingOnDrag) + { + mParentPlot->setAntialiasedElements(mAADragBackup); + mParentPlot->setNotAntialiasedElements(mNotAADragBackup); + mParentPlot->replot(); + } + } +} diff --git a/src/interactions/interaction-dragrange.h b/src/interactions/interaction-dragrange.h new file mode 100644 index 00000000..6f84d62d --- /dev/null +++ b/src/interactions/interaction-dragrange.h @@ -0,0 +1,77 @@ +/*************************************************************************** +** ** +** QCustomPlot, an easy to use, modern plotting widget for Qt ** +** Copyright (C) 2011, 2012, 2013, 2014 Emanuel Eichhammer ** +** ** +** This program is free software: you can redistribute it and/or modify ** +** it under the terms of the GNU General Public License as published by ** +** the Free Software Foundation, either version 3 of the License, or ** +** (at your option) any later version. ** +** ** +** This program is distributed in the hope that it will be useful, ** +** but WITHOUT ANY WARRANTY; without even the implied warranty of ** +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** +** GNU General Public License for more details. ** +** ** +** You should have received a copy of the GNU General Public License ** +** along with this program. If not, see http://www.gnu.org/licenses/. ** +** ** +**************************************************************************** +** Author: Erwan Mathieu ** +** Website/Contact: http://www.qcustomplot.com/ ** +** Date: 12.03.14 ** +** Version: 1.2.0-beta ** +****************************************************************************/ + +#ifndef QCP_INTERACTION_DRAGRANGE_H +#define QCP_INTERACTION_DRAGRANGE_H + +#include "interaction.h" + +class QCPAxis; + + +class QCP_LIB_DECL QCPInteractionDragRange : public QCPAbstractInteraction +{ + Q_OBJECT + /// \cond INCLUDE_QPROPERTIES + Q_PROPERTY(MouseButton button READ button WRITE setButton) + Q_PROPERTY(bool noAntialiasingOnDrag READ noAntialiasingOnDrag WRITE setNoAntialiasingOnDrag) + /// \endcond +public: + QCPInteractionDragRange(QCustomPlot *parentPlot); + virtual ~QCPInteractionDragRange(); + + // getters: + MouseButton button() const { return mButton; } + bool noAntialiasingOnDrag() const { return mNoAntialiasingOnDrag; } + int axisCount() const { return mAxis.count(); } + QCPAxis *axis(int index) const { return mAxis[index]; } + + // setters: + void setButton(MouseButton button) { mButton = button; } + void setNoAntialiasingOnDrag(bool enabled); + void clearAxis() { mAxis.clear(); } + void addAxis(QCPAxis *axis) { mAxis << axis; } + + // reimplemented virtual method: + virtual void mousePressEvent(QMouseEvent *event); + virtual void mouseMoveEvent(QMouseEvent *event); + virtual void mouseReleaseEvent(QMouseEvent *event); + +protected: + // property members + MouseButton mButton; + QList > mAxis; + bool mNoAntialiasingOnDrag; + + // non-property members + QPoint mMousePressPos; + QList mRangesStart; + QCP::AntialiasedElements mAADragBackup, mNotAADragBackup; + +private: + Q_DISABLE_COPY(QCPInteractionDragRange) +}; + +#endif // QCP_INTERACTION_DRAGRANGE_H diff --git a/src/interactions/interaction-select.cpp b/src/interactions/interaction-select.cpp new file mode 100644 index 00000000..9ac3dd87 --- /dev/null +++ b/src/interactions/interaction-select.cpp @@ -0,0 +1,124 @@ +/*************************************************************************** +** ** +** QCustomPlot, an easy to use, modern plotting widget for Qt ** +** Copyright (C) 2011, 2012, 2013, 2014 Emanuel Eichhammer ** +** ** +** This program is free software: you can redistribute it and/or modify ** +** it under the terms of the GNU General Public License as published by ** +** the Free Software Foundation, either version 3 of the License, or ** +** (at your option) any later version. ** +** ** +** This program is distributed in the hope that it will be useful, ** +** but WITHOUT ANY WARRANTY; without even the implied warranty of ** +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** +** GNU General Public License for more details. ** +** ** +** You should have received a copy of the GNU General Public License ** +** along with this program. If not, see http://www.gnu.org/licenses/. ** +** ** +**************************************************************************** +** Author: Erwan Mathieu ** +** Website/Contact: http://www.qcustomplot.com/ ** +** Date: 12.03.14 ** +** Version: 1.2.0-beta ** +****************************************************************************/ + +#include "interaction-select.h" + +#include "axis.h" +#include "core.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////// QCPInteractionSelect +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*! \class QCPInteractionSelect + \brief +*/ + +/* start documentation of inline functions */ + + +/* end documentation of inline functions */ + +QCPInteractionSelect::QCPInteractionSelect(QCustomPlot *parentPlot) : + QCPAbstractInteraction(parentPlot), + mButton(mbLeft), + mMultiSelectModifier(Qt::ControlModifier), + mInteractions(0), + mMousePressPos() +{ +} + +QCPInteractionSelect::~QCPInteractionSelect() +{ +} + +/*! + Sets the keyboard modifier that will be recognized as multi-select-modifier. + + If \ref QCP::iMultiSelect is specified in \ref setInteractions, the user may select multiple objects + by clicking on them one after the other while holding down \a modifier. + + By default the multi-select-modifier is set to Qt::ControlModifier. + + \see setInteractions +*/ +void QCPInteractionSelect::setMultiSelectModifier(Qt::KeyboardModifier modifier) +{ + mMultiSelectModifier = modifier; +} + +void QCPInteractionSelect::mousePressEvent(QMouseEvent *event) +{ + if(toMouseButton(event->button()) == mButton) + { + mMousePressPos = event->pos(); + } +} + +void QCPInteractionSelect::mouseReleaseEvent(QMouseEvent *event) +{ + bool selectionStateChanged = false; + + if(toMouseButton(event->button()) == mButton) + { + if ((mMousePressPos - event->pos()).manhattanLength() < 5) // determine whether it was a click operation + { + QVariant details; + QCPLayerable *clickedLayerable = mParentPlot->layerableAt(event->pos(), true, &details); + bool additive = mInteractions.testFlag(QCP::iMultiSelect) && event->modifiers().testFlag(mMultiSelectModifier); + // deselect all other layerables if not additive selection: + if (!additive) + { + for(int i=0 ; ilayerCount() ; i++) + { + QCPLayer *layer = mParentPlot->layer(i); + + foreach (QCPLayerable *layerable, layer->children()) + { + if (layerable != clickedLayerable && mInteractions.testFlag(layerable->selectionCategory())) + { + bool selChanged = false; + layerable->deselectEvent(&selChanged); + selectionStateChanged |= selChanged; + } + } + } + } + if (clickedLayerable && mInteractions.testFlag(clickedLayerable->selectionCategory())) + { + // a layerable was actually clicked, call its selectEvent: + bool selChanged = false; + clickedLayerable->selectEvent(event, additive, details, &selChanged); + selectionStateChanged |= selChanged; + } + } + } + + if (selectionStateChanged) + { + emit selectionChanged(); + mParentPlot->replot(); + } +} diff --git a/src/interactions/interaction-select.h b/src/interactions/interaction-select.h new file mode 100644 index 00000000..dc3b299d --- /dev/null +++ b/src/interactions/interaction-select.h @@ -0,0 +1,73 @@ +/*************************************************************************** +** ** +** QCustomPlot, an easy to use, modern plotting widget for Qt ** +** Copyright (C) 2011, 2012, 2013, 2014 Emanuel Eichhammer ** +** ** +** This program is free software: you can redistribute it and/or modify ** +** it under the terms of the GNU General Public License as published by ** +** the Free Software Foundation, either version 3 of the License, or ** +** (at your option) any later version. ** +** ** +** This program is distributed in the hope that it will be useful, ** +** but WITHOUT ANY WARRANTY; without even the implied warranty of ** +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** +** GNU General Public License for more details. ** +** ** +** You should have received a copy of the GNU General Public License ** +** along with this program. If not, see http://www.gnu.org/licenses/. ** +** ** +**************************************************************************** +** Author: Erwan Mathieu ** +** Website/Contact: http://www.qcustomplot.com/ ** +** Date: 12.03.14 ** +** Version: 1.2.0-beta ** +****************************************************************************/ + +#ifndef QCP_INTERACTION_SELECT_H +#define QCP_INTERACTION_SELECT_H + +#include "interaction.h" + + +class QCP_LIB_DECL QCPInteractionSelect : public QCPAbstractInteraction +{ + Q_OBJECT + /// \cond INCLUDE_QPROPERTIES + Q_PROPERTY(MouseButton button READ button WRITE setButton) + Q_PROPERTY(Qt::KeyboardModifier multiSelectModifier READ multiSelectModifier WRITE setMultiSelectModifier) + /// \endcond +public: + QCPInteractionSelect(QCustomPlot *parentPlot); + virtual ~QCPInteractionSelect(); + + // getters: + MouseButton button() const { return mButton; } + Qt::KeyboardModifier multiSelectModifier() const { return mMultiSelectModifier; } + QCP::Interactions interactions() const { return mInteractions; } + + // setters: + void setButton(MouseButton button) { mButton = button; } + void setMultiSelectModifier(Qt::KeyboardModifier modifier); + void setInteractions(QCP::Interactions interactions) { mInteractions = interactions; } + + // reimplemented virtual method: + virtual void mousePressEvent(QMouseEvent *event); + virtual void mouseReleaseEvent(QMouseEvent *event); + +signals: + void selectionChanged(); + +protected: + // property members + MouseButton mButton; + Qt::KeyboardModifier mMultiSelectModifier; + QCP::Interactions mInteractions; + + // non-property members + QPoint mMousePressPos; + +private: + Q_DISABLE_COPY(QCPInteractionSelect) +}; + +#endif // QCP_INTERACTION_SELECT_H diff --git a/src/interactions/interaction-zoomrange.cpp b/src/interactions/interaction-zoomrange.cpp index ea2d293c..0c9f0091 100644 --- a/src/interactions/interaction-zoomrange.cpp +++ b/src/interactions/interaction-zoomrange.cpp @@ -100,8 +100,8 @@ QCPInteractionZoomRange::QCPInteractionZoomRange(QCustomPlot *parentPlot) : QCPAbstractInteraction(parentPlot), mButtonZoomIn(mbWheelUp), mButtonZoomOut(mbWheelDown), - mMousePressPos(), - mAxis() + mAxis(), + mMousePressPos() { } @@ -118,32 +118,28 @@ void QCPInteractionZoomRange::setFactor(double factor) } } -bool QCPInteractionZoomRange::mousePressEvent(QMouseEvent *event) +void QCPInteractionZoomRange::mousePressEvent(QMouseEvent *event) { MouseButton button = toMouseButton(event->button()); if(button == mButtonZoomIn || button == mButtonZoomOut) { mMousePressPos = event->pos(); } - - return false; } -bool QCPInteractionZoomRange::mouseReleaseEvent(QMouseEvent *event) +void QCPInteractionZoomRange::mouseReleaseEvent(QMouseEvent *event) { MouseButton button = toMouseButton(event->button()); if(button == mButtonZoomIn || button == mButtonZoomOut) { if ((mMousePressPos - event->pos()).manhattanLength() < 5) // determine whether it was a click operation { - return doZoom(event->pos(), button == mButtonZoomIn ? 1 : -1); + doZoom(event->pos(), button == mButtonZoomIn ? 1 : -1); } } - - return false; } -bool QCPInteractionZoomRange::mouseWheelEvent(QWheelEvent *event) +void QCPInteractionZoomRange::mouseWheelEvent(QWheelEvent *event) { double wheelDelta = event->delta() / 120.0; // a single step delta is +/-120 usually double wise = 0; @@ -164,12 +160,10 @@ bool QCPInteractionZoomRange::mouseWheelEvent(QWheelEvent *event) } if(!qFuzzyIsNull(wise)) - return doZoom(event->pos(), wheelDelta * wise); - - return false; + doZoom(event->pos(), wheelDelta * wise); } -bool QCPInteractionZoomRange::doZoom(const QPoint &pos, double steps) +void QCPInteractionZoomRange::doZoom(const QPoint &pos, double steps) { bool scaled = false; for(int i=0 ; ireplot(); - - return scaled; } diff --git a/src/interactions/interaction-zoomrange.h b/src/interactions/interaction-zoomrange.h index 37084690..0cda880e 100644 --- a/src/interactions/interaction-zoomrange.h +++ b/src/interactions/interaction-zoomrange.h @@ -57,9 +57,9 @@ public: void addAxis(QCPAxis *axis, double factor=0.85) { mAxis << qMakePair(QPointer(axis), factor); } // reimplemented virtual method: - virtual bool mousePressEvent(QMouseEvent *event); - virtual bool mouseReleaseEvent(QMouseEvent *event); - virtual bool mouseWheelEvent(QWheelEvent *event); + virtual void mousePressEvent(QMouseEvent *event); + virtual void mouseReleaseEvent(QMouseEvent *event); + virtual void mouseWheelEvent(QWheelEvent *event); protected: // property members @@ -69,9 +69,10 @@ protected: // non-property members QPoint mMousePressPos; + QCP::AntialiasedElements mAADragBackup, mNotAADragBackup; // non-virtual methods: - bool doZoom(const QPoint &pos, double steps); + void doZoom(const QPoint &pos, double steps); private: Q_DISABLE_COPY(QCPInteractionZoomRange) diff --git a/src/interactions/interaction-zoomrect.cpp b/src/interactions/interaction-zoomrect.cpp index 0b9ecf3d..36fbde73 100644 --- a/src/interactions/interaction-zoomrect.cpp +++ b/src/interactions/interaction-zoomrect.cpp @@ -25,6 +25,8 @@ #include "interaction-zoomrect.h" +#include + #include "axis.h" #include "core.h" @@ -43,9 +45,9 @@ QCPInteractionZoomRect::QCPInteractionZoomRect(QCustomPlot *parentPlot) : QCPAbstractInteraction(parentPlot), - mButtonZoom(mbLeft), - mMousePressPos(), + mButton(mbLeft), mAxis(), + mMousePressPos(), mRubberBand(new QRubberBand(QRubberBand::Rectangle, parentPlot)) { mRubberBand->hide(); @@ -55,28 +57,26 @@ QCPInteractionZoomRect::~QCPInteractionZoomRect() { } -bool QCPInteractionZoomRect::mousePressEvent(QMouseEvent *event) +void QCPInteractionZoomRect::mousePressEvent(QMouseEvent *event) { - if(toMouseButton(event->button()) == mButtonZoom && not mAxis.isEmpty()) + if(toMouseButton(event->button()) == mButton && not mAxis.isEmpty()) { mMousePressPos = event->pos(); mRubberBand->setGeometry(QRect(mMousePressPos, QSize(0, 0))); mRubberBand->show(); } - - return false; } -bool QCPInteractionZoomRect::mouseMoveEvent(QMouseEvent *event) +void QCPInteractionZoomRect::mouseMoveEvent(QMouseEvent *event) { if(mRubberBand->isVisible()) mRubberBand->setGeometry(QRect(mMousePressPos, event->pos()).normalized()); } -bool QCPInteractionZoomRect::mouseReleaseEvent(QMouseEvent *event) +void QCPInteractionZoomRect::mouseReleaseEvent(QMouseEvent *event) { bool ranged = false; - if(toMouseButton(event->button()) == mButtonZoom && mRubberBand->isVisible()) + if(toMouseButton(event->button()) == mButton && mRubberBand->isVisible()) { mRubberBand->hide(); QRect rect = mRubberBand->geometry(); @@ -111,6 +111,4 @@ bool QCPInteractionZoomRect::mouseReleaseEvent(QMouseEvent *event) if(ranged) mParentPlot->replot(); - - return ranged; } diff --git a/src/interactions/interaction-zoomrect.h b/src/interactions/interaction-zoomrect.h index da4391fd..0f6b80de 100644 --- a/src/interactions/interaction-zoomrect.h +++ b/src/interactions/interaction-zoomrect.h @@ -36,30 +36,30 @@ class QCP_LIB_DECL QCPInteractionZoomRect : public QCPAbstractInteraction { Q_OBJECT /// \cond INCLUDE_QPROPERTIES - Q_PROPERTY(MouseButton buttonZoom READ buttonZoom WRITE setButtonZoom) + Q_PROPERTY(MouseButton button READ button WRITE setButton) /// \endcond public: QCPInteractionZoomRect(QCustomPlot *parentPlot); virtual ~QCPInteractionZoomRect(); // getters: - MouseButton buttonZoom() const { return mButtonZoom; } + MouseButton button() const { return mButton; } int axisCount() const { return mAxis.count(); } QCPAxis *axis(int index) const { return mAxis[index]; } // setters: - void setButtonZoom(MouseButton button) { mButtonZoom = button; } + void setButton(MouseButton button) { mButton = button; } void clearAxis() { mAxis.clear(); } void addAxis(QCPAxis *axis) { mAxis << axis; } // reimplemented virtual method: - virtual bool mousePressEvent(QMouseEvent *event); - virtual bool mouseMoveEvent(QMouseEvent *event); - virtual bool mouseReleaseEvent(QMouseEvent *event); + virtual void mousePressEvent(QMouseEvent *event); + virtual void mouseMoveEvent(QMouseEvent *event); + virtual void mouseReleaseEvent(QMouseEvent *event); protected: // property members - MouseButton mButtonZoom; + MouseButton mButton; QList > mAxis; // non-property members diff --git a/src/layer.h b/src/layer.h index e5b7aa29..70041346 100644 --- a/src/layer.h +++ b/src/layer.h @@ -106,6 +106,10 @@ public: // introduced virtual methods: virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=0) const; + virtual QCP::Interaction selectionCategory() const; + // events: + virtual void selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged); + virtual void deselectEvent(bool *selectionStateChanged); // non-property methods: bool realVisibility() const; @@ -123,13 +127,9 @@ protected: // introduced virtual methods: virtual void parentPlotInitialized(QCustomPlot *parentPlot); - virtual QCP::Interaction selectionCategory() const; virtual QRect clipRect() const; virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const = 0; virtual void draw(QCPPainter *painter) = 0; - // events: - virtual void selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged); - virtual void deselectEvent(bool *selectionStateChanged); // non-property methods: void initializeParentPlot(QCustomPlot *parentPlot); diff --git a/src/layoutelements/layoutelement-axisrect.cpp b/src/layoutelements/layoutelement-axisrect.cpp index 79f34f12..3deb1cd3 100644 --- a/src/layoutelements/layoutelement-axisrect.cpp +++ b/src/layoutelements/layoutelement-axisrect.cpp @@ -167,10 +167,7 @@ QCPAxisRect::QCPAxisRect(QCustomPlot *parentPlot, bool setupDefaultAxes) : mBackgroundBrush(Qt::NoBrush), mBackgroundScaled(true), mBackgroundScaledMode(Qt::KeepAspectRatioByExpanding), - mInsetLayout(new QCPLayoutInset), - mRangeDrag(Qt::Horizontal|Qt::Vertical), - mDragging(false), - mZoomRubber(new QRubberBand(QRubberBand::Rectangle, parentPlot)) + mInsetLayout(new QCPLayoutInset) { mInsetLayout->initializeParentPlot(mParentPlot); mInsetLayout->setParentLayerable(this); @@ -189,7 +186,6 @@ QCPAxisRect::QCPAxisRect(QCustomPlot *parentPlot, bool setupDefaultAxes) : QCPAxis *yAxis = addAxis(QCPAxis::atLeft); QCPAxis *xAxis2 = addAxis(QCPAxis::atTop); QCPAxis *yAxis2 = addAxis(QCPAxis::atRight); - setRangeDragAxes(xAxis, yAxis); xAxis2->setVisible(false); yAxis2->setVisible(false); xAxis->grid()->setVisible(true); @@ -201,8 +197,6 @@ QCPAxisRect::QCPAxisRect(QCustomPlot *parentPlot, bool setupDefaultAxes) : xAxis2->grid()->setVisible(false); yAxis2->grid()->setVisible(false); } - - mZoomRubber->hide(); } QCPAxisRect::~QCPAxisRect() @@ -661,50 +655,6 @@ void QCPAxisRect::setBackgroundScaledMode(Qt::AspectRatioMode mode) mBackgroundScaledMode = mode; } -/*! - Returns the range drag axis of the \a orientation provided. - - \see setRangeDragAxes -*/ -QCPAxis *QCPAxisRect::rangeDragAxis(Qt::Orientation orientation) -{ - return (orientation == Qt::Horizontal ? mRangeDragHorzAxis.data() : mRangeDragVertAxis.data()); -} - - -/*! - Sets which axis orientation may be range dragged by the user with mouse interaction. - What orientation corresponds to which specific axis can be set with - \ref setRangeDragAxes(QCPAxis *horizontal, QCPAxis *vertical). By - default, the horizontal axis is the bottom axis (xAxis) and the vertical axis - is the left axis (yAxis). - - To disable range dragging entirely, pass 0 as \a orientations or remove \ref QCP::iRangeDrag from \ref - QCustomPlot::setInteractions. To enable range dragging for both directions, pass Qt::Horizontal | - Qt::Vertical as \a orientations. - - In addition to setting \a orientations to a non-zero value, make sure \ref QCustomPlot::setInteractions - contains \ref QCP::iRangeDrag to enable the range dragging interaction. - - \see setRangeZoom, setRangeDragAxes, setNoAntialiasingOnDrag -*/ -void QCPAxisRect::setRangeDrag(Qt::Orientations orientations) -{ - mRangeDrag = orientations; -} - -/*! - Sets the axes whose range will be dragged when \ref setRangeDrag enables mouse range dragging - on the QCustomPlot widget. - - \see setRangeZoomAxes -*/ -void QCPAxisRect::setRangeDragAxes(QCPAxis *horizontal, QCPAxis *vertical) -{ - mRangeDragHorzAxis = horizontal; - mRangeDragVertAxis = vertical; -} - /*! \internal Draws the background of this axis rect. It may consist of a background fill (a QBrush) and a @@ -779,103 +729,3 @@ int QCPAxisRect::calculateAutoMargin(QCP::MarginSide side) else return 0; } - -/*! \internal - - Event handler for when a mouse button is pressed on the axis rect. If the left mouse button is - pressed, the range dragging interaction is initialized (the actual range manipulation happens in - the \ref mouseMoveEvent). - - The mDragging flag is set to true and some anchor points are set that are needed to determine the - distance the mouse was dragged in the mouse move/release events later. - - \see mouseMoveEvent, mouseReleaseEvent -*/ -void QCPAxisRect::mousePressEvent(QMouseEvent *event) -{ - mDragStart = event->pos(); // need this even when not LeftButton is pressed, to determine in releaseEvent whether it was a full click (no position change between press and release) - if (event->button() == Qt::LeftButton) - { - mDragging = true; - // initialize antialiasing backup in case we start dragging: - if (mParentPlot->noAntialiasingOnDrag()) - { - mAADragBackup = mParentPlot->antialiasedElements(); - mNotAADragBackup = mParentPlot->notAntialiasedElements(); - } - // Mouse range dragging interaction: - if (mParentPlot->interactions().testFlag(QCP::iRangeDrag)) - { - if (mRangeDragHorzAxis) - mDragStartHorzRange = mRangeDragHorzAxis.data()->range(); - if (mRangeDragVertAxis) - mDragStartVertRange = mRangeDragVertAxis.data()->range(); - } - } -} - -/*! \internal - - Event handler for when the mouse is moved on the axis rect. If range dragging was activated in a - preceding \ref mousePressEvent, the range is moved accordingly. - - \see mousePressEvent, mouseReleaseEvent -*/ -void QCPAxisRect::mouseMoveEvent(QMouseEvent *event) -{ - // Mouse range dragging interaction: - if (mDragging) - { - if (mParentPlot->interactions().testFlag(QCP::iRangeDrag)) - { - if (mRangeDrag.testFlag(Qt::Horizontal)) - { - if (QCPAxis *rangeDragHorzAxis = mRangeDragHorzAxis.data()) - { - if (rangeDragHorzAxis->mScaleType == QCPAxis::stLinear) - { - double diff = rangeDragHorzAxis->pixelToCoord(mDragStart.x()) - rangeDragHorzAxis->pixelToCoord(event->pos().x()); - rangeDragHorzAxis->setRange(mDragStartHorzRange.lower+diff, mDragStartHorzRange.upper+diff); - } else if (rangeDragHorzAxis->mScaleType == QCPAxis::stLogarithmic) - { - double diff = rangeDragHorzAxis->pixelToCoord(mDragStart.x()) / rangeDragHorzAxis->pixelToCoord(event->pos().x()); - rangeDragHorzAxis->setRange(mDragStartHorzRange.lower*diff, mDragStartHorzRange.upper*diff); - } - } - } - if (mRangeDrag.testFlag(Qt::Vertical)) - { - if (QCPAxis *rangeDragVertAxis = mRangeDragVertAxis.data()) - { - if (rangeDragVertAxis->mScaleType == QCPAxis::stLinear) - { - double diff = rangeDragVertAxis->pixelToCoord(mDragStart.y()) - rangeDragVertAxis->pixelToCoord(event->pos().y()); - rangeDragVertAxis->setRange(mDragStartVertRange.lower+diff, mDragStartVertRange.upper+diff); - } else if (rangeDragVertAxis->mScaleType == QCPAxis::stLogarithmic) - { - double diff = rangeDragVertAxis->pixelToCoord(mDragStart.y()) / rangeDragVertAxis->pixelToCoord(event->pos().y()); - rangeDragVertAxis->setRange(mDragStartVertRange.lower*diff, mDragStartVertRange.upper*diff); - } - } - } - if (mRangeDrag != 0) // if either vertical or horizontal drag was enabled, do a replot - { - if (mParentPlot->noAntialiasingOnDrag()) - mParentPlot->setNotAntialiasedElements(QCP::aeAll); - mParentPlot->replot(); - } - } - } -} - -/* inherits documentation from base class */ -void QCPAxisRect::mouseReleaseEvent(QMouseEvent *event) -{ - Q_UNUSED(event) - mDragging = false; - if (mParentPlot->noAntialiasingOnDrag()) - { - mParentPlot->setAntialiasedElements(mAADragBackup); - mParentPlot->setNotAntialiasedElements(mNotAADragBackup); - } -} diff --git a/src/layoutelements/layoutelement-axisrect.h b/src/layoutelements/layoutelement-axisrect.h index d4f496d6..c4eaa3f3 100644 --- a/src/layoutelements/layoutelement-axisrect.h +++ b/src/layoutelements/layoutelement-axisrect.h @@ -44,7 +44,6 @@ class QCP_LIB_DECL QCPAxisRect : public QCPLayoutElement Q_PROPERTY(QPixmap background READ background WRITE setBackground) Q_PROPERTY(bool backgroundScaled READ backgroundScaled WRITE setBackgroundScaled) Q_PROPERTY(Qt::AspectRatioMode backgroundScaledMode READ backgroundScaledMode WRITE setBackgroundScaledMode) - Q_PROPERTY(Qt::Orientations rangeDrag READ rangeDrag WRITE setRangeDrag) /// \endcond public: explicit QCPAxisRect(QCustomPlot *parentPlot, bool setupDefaultAxes=true); @@ -54,8 +53,6 @@ public: QPixmap background() const { return mBackgroundPixmap; } bool backgroundScaled() const { return mBackgroundScaled; } Qt::AspectRatioMode backgroundScaledMode() const { return mBackgroundScaledMode; } - Qt::Orientations rangeDrag() const { return mRangeDrag; } - QCPAxis *rangeDragAxis(Qt::Orientation orientation); // setters: void setBackground(const QPixmap &pm); @@ -63,8 +60,6 @@ public: void setBackground(const QBrush &brush); void setBackgroundScaled(bool scaled); void setBackgroundScaledMode(Qt::AspectRatioMode mode); - void setRangeDrag(Qt::Orientations orientations); - void setRangeDragAxes(QCPAxis *horizontal, QCPAxis *vertical); // non-property methods: int axisCount(QCPAxis::AxisType type) const; @@ -107,24 +102,13 @@ protected: bool mBackgroundScaled; Qt::AspectRatioMode mBackgroundScaledMode; QCPLayoutInset *mInsetLayout; - Qt::Orientations mRangeDrag; - QPointer mRangeDragHorzAxis, mRangeDragVertAxis; // non-property members: - QCPRange mDragStartHorzRange, mDragStartVertRange; - QCP::AntialiasedElements mAADragBackup, mNotAADragBackup; - QPoint mDragStart; - bool mDragging; QHash > mAxes; - QRubberBand *mZoomRubber; // reimplemented virtual methods: virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const; virtual void draw(QCPPainter *painter); virtual int calculateAutoMargin(QCP::MarginSide side); - // events: - virtual void mousePressEvent(QMouseEvent *event); - virtual void mouseMoveEvent(QMouseEvent *event); - virtual void mouseReleaseEvent(QMouseEvent *event); // non-property methods: void drawBackground(QCPPainter *painter); diff --git a/src/layoutelements/layoutelement-colorscale.cpp b/src/layoutelements/layoutelement-colorscale.cpp index 6b4ddb8d..b3127a50 100644 --- a/src/layoutelements/layoutelement-colorscale.cpp +++ b/src/layoutelements/layoutelement-colorscale.cpp @@ -157,20 +157,6 @@ QString QCPColorScale::label() const return mColorAxis.data()->label(); } -/* undocumented getter */ -bool QCPColorScale::rangeDrag() const -{ - if (!mAxisRect) - { - qDebug() << Q_FUNC_INFO << "internal axis rect was deleted"; - return false; - } - - return mAxisRect.data()->rangeDrag().testFlag(QCPAxis::orientation(mType)) && - mAxisRect.data()->rangeDragAxis(QCPAxis::orientation(mType)) && - mAxisRect.data()->rangeDragAxis(QCPAxis::orientation(mType))->orientation() == QCPAxis::orientation(mType); -} - /*! Sets at which side of the color scale the axis is placed, and thus also its orientation. @@ -214,8 +200,6 @@ void QCPColorScale::setType(QCPAxis::AxisType type) mColorAxis.data()->setScaleLogBase(logBaseTransfer); // scaleType is synchronized among axes in realtime via signals (connected in QCPColorScale ctor), so we only need to take care of log base here connect(mColorAxis.data(), SIGNAL(rangeChanged(QCPRange)), this, SLOT(setDataRange(QCPRange))); connect(mColorAxis.data(), SIGNAL(scaleTypeChanged(QCPAxis::ScaleType)), this, SLOT(setDataScaleType(QCPAxis::ScaleType))); - mAxisRect.data()->setRangeDragAxes(QCPAxis::orientation(mType) == Qt::Horizontal ? mColorAxis.data() : 0, - QCPAxis::orientation(mType) == Qt::Vertical ? mColorAxis.data() : 0); } } @@ -304,26 +288,6 @@ void QCPColorScale::setBarWidth(int width) mBarWidth = width; } -/*! - Sets whether the user can drag the data range (\ref setDataRange). - - Note that \ref QCP::iRangeDrag must be in the QCustomPlot's interactions (\ref - QCustomPlot::setInteractions) to allow range dragging. -*/ -void QCPColorScale::setRangeDrag(bool enabled) -{ - if (!mAxisRect) - { - qDebug() << Q_FUNC_INFO << "internal axis rect was deleted"; - return; - } - - if (enabled) - mAxisRect.data()->setRangeDrag(QCPAxis::orientation(mType)); - else - mAxisRect.data()->setRangeDrag(0); -} - /* inherits documentation from base class */ void QCPColorScale::update(UpdatePhase phase) { diff --git a/src/layoutelements/layoutelement-colorscale.h b/src/layoutelements/layoutelement-colorscale.h index 1cb17019..8ac1d4ae 100644 --- a/src/layoutelements/layoutelement-colorscale.h +++ b/src/layoutelements/layoutelement-colorscale.h @@ -72,7 +72,6 @@ class QCP_LIB_DECL QCPColorScale : public QCPLayoutElement Q_PROPERTY(QCPColorGradient gradient READ gradient WRITE setGradient NOTIFY gradientChanged) Q_PROPERTY(QString label READ label WRITE setLabel) Q_PROPERTY(int barWidth READ barWidth WRITE setBarWidth) - Q_PROPERTY(bool rangeDrag READ rangeDrag WRITE setRangeDrag) /// \endcond public: explicit QCPColorScale(QCustomPlot *parentPlot); @@ -86,7 +85,6 @@ public: QCPColorGradient gradient() const { return mGradient; } QString label() const; int barWidth () const { return mBarWidth; } - bool rangeDrag() const; // setters: void setType(QCPAxis::AxisType type); @@ -95,8 +93,6 @@ public: Q_SLOT void setGradient(const QCPColorGradient &gradient); void setLabel(const QString &str); void setBarWidth(int width); - void setRangeDrag(bool enabled); - void setRangeZoom(bool enabled); // non-property methods: -- GitLab From 3704b176ad0c0cbf98c0dec5f67e6414aacb6424 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 13 Mar 2014 10:19:17 +0100 Subject: [PATCH 06/10] Refactoring to make amalgamation work properly --- src/global.h | 1 + src/interaction.h | 2 +- src/interactions/interaction-dragrange.cpp | 6 +++--- src/interactions/interaction-dragrange.h | 4 ++-- src/interactions/interaction-select.cpp | 4 ++-- src/interactions/interaction-select.h | 4 ++-- src/interactions/interaction-zoomrange.cpp | 4 ++-- src/interactions/interaction-zoomrange.h | 6 +++--- src/interactions/interaction-zoomrect.cpp | 6 ++---- src/interactions/interaction-zoomrect.h | 4 ++-- src/qcustomplot.cpp.skeleton | 5 +++++ src/qcustomplot.h.skeleton | 5 +++++ 12 files changed, 30 insertions(+), 21 deletions(-) diff --git a/src/global.h b/src/global.h index d7dc46eb..8187cf03 100644 --- a/src/global.h +++ b/src/global.h @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) diff --git a/src/interaction.h b/src/interaction.h index ccfc2925..3bf8aa9c 100644 --- a/src/interaction.h +++ b/src/interaction.h @@ -48,7 +48,7 @@ public: ,mbWheelDown ///< Pseudo-button, use when the wheel has been moved down ,mbXButton1 ///< First optional mouse button, usually located on the side ,mbXButton2 ///< Seconcd optional mouse button, usually located on the side - }; + }; QCPAbstractInteraction(QCustomPlot *parentPlot); virtual ~QCPAbstractInteraction(); diff --git a/src/interactions/interaction-dragrange.cpp b/src/interactions/interaction-dragrange.cpp index c8558d82..229c588b 100644 --- a/src/interactions/interaction-dragrange.cpp +++ b/src/interactions/interaction-dragrange.cpp @@ -25,8 +25,8 @@ #include "interaction-dragrange.h" -#include "axis.h" -#include "core.h" +#include "../axis.h" +#include "../core.h" //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPInteractionDragRange @@ -45,7 +45,7 @@ QCPInteractionDragRange::QCPInteractionDragRange(QCustomPlot *parentPlot) : QCPAbstractInteraction(parentPlot), mButton(mbLeft), mAxis(), - mNoAntialiasingOnDrag(true), + mNoAntialiasingOnDrag(false), mMousePressPos(), mRangesStart() { diff --git a/src/interactions/interaction-dragrange.h b/src/interactions/interaction-dragrange.h index 6f84d62d..26cbbbb6 100644 --- a/src/interactions/interaction-dragrange.h +++ b/src/interactions/interaction-dragrange.h @@ -26,7 +26,7 @@ #ifndef QCP_INTERACTION_DRAGRANGE_H #define QCP_INTERACTION_DRAGRANGE_H -#include "interaction.h" +#include "../interaction.h" class QCPAxis; @@ -35,7 +35,7 @@ class QCP_LIB_DECL QCPInteractionDragRange : public QCPAbstractInteraction { Q_OBJECT /// \cond INCLUDE_QPROPERTIES - Q_PROPERTY(MouseButton button READ button WRITE setButton) + Q_PROPERTY(QCPAbstractInteraction::MouseButton button READ button WRITE setButton) Q_PROPERTY(bool noAntialiasingOnDrag READ noAntialiasingOnDrag WRITE setNoAntialiasingOnDrag) /// \endcond public: diff --git a/src/interactions/interaction-select.cpp b/src/interactions/interaction-select.cpp index 9ac3dd87..c4022df4 100644 --- a/src/interactions/interaction-select.cpp +++ b/src/interactions/interaction-select.cpp @@ -25,8 +25,8 @@ #include "interaction-select.h" -#include "axis.h" -#include "core.h" +#include "../axis.h" +#include "../core.h" //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPInteractionSelect diff --git a/src/interactions/interaction-select.h b/src/interactions/interaction-select.h index dc3b299d..1cdec133 100644 --- a/src/interactions/interaction-select.h +++ b/src/interactions/interaction-select.h @@ -26,14 +26,14 @@ #ifndef QCP_INTERACTION_SELECT_H #define QCP_INTERACTION_SELECT_H -#include "interaction.h" +#include "../interaction.h" class QCP_LIB_DECL QCPInteractionSelect : public QCPAbstractInteraction { Q_OBJECT /// \cond INCLUDE_QPROPERTIES - Q_PROPERTY(MouseButton button READ button WRITE setButton) + Q_PROPERTY(QCPAbstractInteraction::MouseButton button READ button WRITE setButton) Q_PROPERTY(Qt::KeyboardModifier multiSelectModifier READ multiSelectModifier WRITE setMultiSelectModifier) /// \endcond public: diff --git a/src/interactions/interaction-zoomrange.cpp b/src/interactions/interaction-zoomrange.cpp index 0c9f0091..07cab6b9 100644 --- a/src/interactions/interaction-zoomrange.cpp +++ b/src/interactions/interaction-zoomrange.cpp @@ -25,8 +25,8 @@ #include "interaction-zoomrange.h" -#include "axis.h" -#include "core.h" +#include "../axis.h" +#include "../core.h" //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPInteractionZoomRange diff --git a/src/interactions/interaction-zoomrange.h b/src/interactions/interaction-zoomrange.h index 0cda880e..a1384506 100644 --- a/src/interactions/interaction-zoomrange.h +++ b/src/interactions/interaction-zoomrange.h @@ -26,7 +26,7 @@ #ifndef QCP_INTERACTION_ZOOMRANGE_H #define QCP_INTERACTION_ZOOMRANGE_H -#include "interaction.h" +#include "../interaction.h" class QCPAxis; @@ -35,8 +35,8 @@ class QCP_LIB_DECL QCPInteractionZoomRange : public QCPAbstractInteraction { Q_OBJECT /// \cond INCLUDE_QPROPERTIES - Q_PROPERTY(MouseButton buttonZoomIn READ buttonZoomIn WRITE setButtonZoomIn) - Q_PROPERTY(MouseButton buttonZoomOut READ buttonZoomOut WRITE setButtonZoomOut) + Q_PROPERTY(QCPAbstractInteraction::MouseButton buttonZoomIn READ buttonZoomIn WRITE setButtonZoomIn) + Q_PROPERTY(QCPAbstractInteraction::MouseButton buttonZoomOut READ buttonZoomOut WRITE setButtonZoomOut) /// \endcond public: QCPInteractionZoomRange(QCustomPlot *parentPlot); diff --git a/src/interactions/interaction-zoomrect.cpp b/src/interactions/interaction-zoomrect.cpp index 36fbde73..c0948721 100644 --- a/src/interactions/interaction-zoomrect.cpp +++ b/src/interactions/interaction-zoomrect.cpp @@ -25,10 +25,8 @@ #include "interaction-zoomrect.h" -#include - -#include "axis.h" -#include "core.h" +#include "../axis.h" +#include "../core.h" //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPInteractionZoomRect diff --git a/src/interactions/interaction-zoomrect.h b/src/interactions/interaction-zoomrect.h index 0f6b80de..16ad3be5 100644 --- a/src/interactions/interaction-zoomrect.h +++ b/src/interactions/interaction-zoomrect.h @@ -26,7 +26,7 @@ #ifndef QCP_INTERACTION_ZOOMRECT_H #define QCP_INTERACTION_ZOOMRECT_H -#include "interaction.h" +#include "../interaction.h" class QRubberBand; class QCPAxis; @@ -36,7 +36,7 @@ class QCP_LIB_DECL QCPInteractionZoomRect : public QCPAbstractInteraction { Q_OBJECT /// \cond INCLUDE_QPROPERTIES - Q_PROPERTY(MouseButton button READ button WRITE setButton) + Q_PROPERTY(QCPAbstractInteraction::MouseButton button READ button WRITE setButton) /// \endcond public: QCPInteractionZoomRect(QCustomPlot *parentPlot); diff --git a/src/qcustomplot.cpp.skeleton b/src/qcustomplot.cpp.skeleton index efd85a53..1bf624ad 100644 --- a/src/qcustomplot.cpp.skeleton +++ b/src/qcustomplot.cpp.skeleton @@ -37,6 +37,7 @@ //amalgamation: add item.cpp //amalgamation: add core.cpp //amalgamation: add colorgradient.cpp +//amalgamation: add interaction.cpp //amalgamation: add layoutelements/layoutelement-axisrect.cpp //amalgamation: add layoutelements/layoutelement-legend.cpp //amalgamation: add layoutelements/layoutelement-plottitle.cpp @@ -55,4 +56,8 @@ //amalgamation: add items/item-pixmap.cpp //amalgamation: add items/item-tracer.cpp //amalgamation: add items/item-bracket.cpp +//amalgamation: add interactions/interaction-dragrange.cpp +//amalgamation: add interactions/interaction-select.cpp +//amalgamation: add interactions/interaction-zoomrange.cpp +//amalgamation: add interactions/interaction-zoomrect.cpp diff --git a/src/qcustomplot.h.skeleton b/src/qcustomplot.h.skeleton index 57ab0f1f..fc9e3277 100644 --- a/src/qcustomplot.h.skeleton +++ b/src/qcustomplot.h.skeleton @@ -40,6 +40,7 @@ //amalgamation: add item.h //amalgamation: add core.h //amalgamation: add colorgradient.h +//amalgamation: add interaction.h //amalgamation: add layoutelements/layoutelement-axisrect.h //amalgamation: add layoutelements/layoutelement-legend.h //amalgamation: add layoutelements/layoutelement-plottitle.h @@ -58,6 +59,10 @@ //amalgamation: add items/item-pixmap.h //amalgamation: add items/item-tracer.h //amalgamation: add items/item-bracket.h +//amalgamation: add interactions/interaction-dragrange.h +//amalgamation: add interactions/interaction-select.h +//amalgamation: add interactions/interaction-zoomrange.h +//amalgamation: add interactions/interaction-zoomrect.h #endif // QCUSTOMPLOT_H -- GitLab From 698720eadab96ab4441ea12f88a66467683b9349 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 21 Mar 2014 16:32:18 +0100 Subject: [PATCH 07/10] Added keyboard modifiers on interactions --- src/interaction.h | 2 + src/interactions/interaction-dragrange.cpp | 88 +++++++++++----------- src/interactions/interaction-dragrange.h | 12 +-- src/interactions/interaction-onebutton.cpp | 64 ++++++++++++++++ src/interactions/interaction-onebutton.h | 76 +++++++++++++++++++ src/interactions/interaction-select.cpp | 61 +++++++-------- src/interactions/interaction-select.h | 12 +-- src/interactions/interaction-zoomrect.cpp | 26 ++++--- src/interactions/interaction-zoomrect.h | 14 +--- src/qcustomplot.cpp.skeleton | 1 + src/qcustomplot.h.skeleton | 1 + 11 files changed, 242 insertions(+), 115 deletions(-) create mode 100644 src/interactions/interaction-onebutton.cpp create mode 100644 src/interactions/interaction-onebutton.h diff --git a/src/interaction.h b/src/interaction.h index 3bf8aa9c..76f36226 100644 --- a/src/interaction.h +++ b/src/interaction.h @@ -66,6 +66,8 @@ public: virtual void mouseMoveEvent(QMouseEvent *event) { Q_UNUSED(event); } virtual void mouseReleaseEvent(QMouseEvent *event) { Q_UNUSED(event); } virtual void mouseWheelEvent(QWheelEvent *event) { Q_UNUSED(event); } + virtual void keyPressEvent(QKeyEvent *event) { Q_UNUSED(event); } + virtual void keyReleaseEvent(QKeyEvent *event) { Q_UNUSED(event); } // static methods: MouseButton toMouseButton(Qt::MouseButton button); diff --git a/src/interactions/interaction-dragrange.cpp b/src/interactions/interaction-dragrange.cpp index 229c588b..d7c33e02 100644 --- a/src/interactions/interaction-dragrange.cpp +++ b/src/interactions/interaction-dragrange.cpp @@ -42,8 +42,7 @@ /* end documentation of inline functions */ QCPInteractionDragRange::QCPInteractionDragRange(QCustomPlot *parentPlot) : - QCPAbstractInteraction(parentPlot), - mButton(mbLeft), + QCPAbstractInteractionOneButton(parentPlot), mAxis(), mNoAntialiasingOnDrag(false), mMousePressPos(), @@ -67,9 +66,9 @@ void QCPInteractionDragRange::setNoAntialiasingOnDrag(bool enabled) mNoAntialiasingOnDrag = enabled; } -void QCPInteractionDragRange::mousePressEvent(QMouseEvent *event) +void QCPInteractionDragRange::buttonActivated(QMouseEvent *event) { - if(toMouseButton(event->button()) == mButton && not mAxis.isEmpty()) + if (not mAxis.isEmpty()) { mMousePressPos = event->pos(); @@ -81,9 +80,9 @@ void QCPInteractionDragRange::mousePressEvent(QMouseEvent *event) } mRangesStart.clear(); - foreach(QPointer axis, mAxis) + foreach (QPointer axis, mAxis) { - if(not axis.isNull()) + if (not axis.isNull()) { mRangesStart << axis->range(); } @@ -95,55 +94,58 @@ void QCPInteractionDragRange::mouseMoveEvent(QMouseEvent *event) { bool ranged = false; - if(not mMousePressPos.isNull()) + if (not mMousePressPos.isNull()) { - int i=0; - foreach(QPointer axis, mAxis) + int i=0; + foreach (QPointer axis, mAxis) + { + if (not axis.isNull()) { - if(not axis.isNull()) - { - QCPRange rangeStart = mRangesStart[i++]; - int dragStart, mousePos; - if(axis->axisType() == QCPAxis::atLeft || axis->axisType() == QCPAxis::atRight) - { - // vertical axis, take the y position of the mouse - dragStart = mMousePressPos.y(); - mousePos = event->pos().y(); - } - else - { - // horizontal axis, take the x position of the mouse - dragStart = mMousePressPos.x(); - mousePos = event->pos().x(); - } - - if (axis->scaleType() == QCPAxis::stLinear) - { - double diff = axis->pixelToCoord(dragStart) - axis->pixelToCoord(mousePos); - axis->setRange(rangeStart.lower + diff, rangeStart.upper + diff); - ranged = true; - } - else if (axis->scaleType() == QCPAxis::stLogarithmic) - { - double diff = axis->pixelToCoord(dragStart) / axis->pixelToCoord(mousePos); - axis->setRange(rangeStart.lower * diff, rangeStart.upper * diff); - ranged = true; - } - } + QCPRange rangeStart = mRangesStart[i++]; + int dragStart, mousePos; + if (axis->axisType() == QCPAxis::atLeft || axis->axisType() == QCPAxis::atRight) + { + // vertical axis, take the y position of the mouse + dragStart = mMousePressPos.y(); + mousePos = event->pos().y(); + } + else + { + // horizontal axis, take the x position of the mouse + dragStart = mMousePressPos.x(); + mousePos = event->pos().x(); + } + + if (axis->scaleType() == QCPAxis::stLinear) + { + double diff = axis->pixelToCoord(dragStart) - axis->pixelToCoord(mousePos); + axis->setRange(rangeStart.lower + diff, rangeStart.upper + diff); + ranged = true; + } + else if (axis->scaleType() == QCPAxis::stLogarithmic) + { + double diff = axis->pixelToCoord(dragStart) / axis->pixelToCoord(mousePos); + axis->setRange(rangeStart.lower * diff, rangeStart.upper * diff); + ranged = true; + } } + } } - if(ranged) + if (ranged) { if (mNoAntialiasingOnDrag) - mParentPlot->setNotAntialiasedElements(QCP::aeAll); + mParentPlot->setNotAntialiasedElements(QCP::aeAll); mParentPlot->replot(); } + + QCPAbstractInteractionOneButton::mouseMoveEvent(event); } -void QCPInteractionDragRange::mouseReleaseEvent(QMouseEvent *event) +void QCPInteractionDragRange::buttonDeactivated(QMouseEvent *event) { - if(toMouseButton(event->button()) == mButton && not mMousePressPos.isNull()) + Q_UNUSED(event) + if (not mMousePressPos.isNull()) { mMousePressPos = QPoint(); if (mNoAntialiasingOnDrag) diff --git a/src/interactions/interaction-dragrange.h b/src/interactions/interaction-dragrange.h index 26cbbbb6..effd2395 100644 --- a/src/interactions/interaction-dragrange.h +++ b/src/interactions/interaction-dragrange.h @@ -26,16 +26,15 @@ #ifndef QCP_INTERACTION_DRAGRANGE_H #define QCP_INTERACTION_DRAGRANGE_H -#include "../interaction.h" +#include "interaction-onebutton.h" class QCPAxis; -class QCP_LIB_DECL QCPInteractionDragRange : public QCPAbstractInteraction +class QCP_LIB_DECL QCPInteractionDragRange : public QCPAbstractInteractionOneButton { Q_OBJECT /// \cond INCLUDE_QPROPERTIES - Q_PROPERTY(QCPAbstractInteraction::MouseButton button READ button WRITE setButton) Q_PROPERTY(bool noAntialiasingOnDrag READ noAntialiasingOnDrag WRITE setNoAntialiasingOnDrag) /// \endcond public: @@ -43,25 +42,22 @@ public: virtual ~QCPInteractionDragRange(); // getters: - MouseButton button() const { return mButton; } bool noAntialiasingOnDrag() const { return mNoAntialiasingOnDrag; } int axisCount() const { return mAxis.count(); } QCPAxis *axis(int index) const { return mAxis[index]; } // setters: - void setButton(MouseButton button) { mButton = button; } void setNoAntialiasingOnDrag(bool enabled); void clearAxis() { mAxis.clear(); } void addAxis(QCPAxis *axis) { mAxis << axis; } // reimplemented virtual method: - virtual void mousePressEvent(QMouseEvent *event); + virtual void buttonActivated(QMouseEvent *event); virtual void mouseMoveEvent(QMouseEvent *event); - virtual void mouseReleaseEvent(QMouseEvent *event); + virtual void buttonDeactivated(QMouseEvent *event); protected: // property members - MouseButton mButton; QList > mAxis; bool mNoAntialiasingOnDrag; diff --git a/src/interactions/interaction-onebutton.cpp b/src/interactions/interaction-onebutton.cpp new file mode 100644 index 00000000..162d589c --- /dev/null +++ b/src/interactions/interaction-onebutton.cpp @@ -0,0 +1,64 @@ +/*************************************************************************** +** ** +** QCustomPlot, an easy to use, modern plotting widget for Qt ** +** Copyright (C) 2011, 2012, 2013, 2014 Emanuel Eichhammer ** +** ** +** This program is free software: you can redistribute it and/or modify ** +** it under the terms of the GNU General Public License as published by ** +** the Free Software Foundation, either version 3 of the License, or ** +** (at your option) any later version. ** +** ** +** This program is distributed in the hope that it will be useful, ** +** but WITHOUT ANY WARRANTY; without even the implied warranty of ** +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** +** GNU General Public License for more details. ** +** ** +** You should have received a copy of the GNU General Public License ** +** along with this program. If not, see http://www.gnu.org/licenses/. ** +** ** +**************************************************************************** +** Author: Erwan Mathieu ** +** Website/Contact: http://www.qcustomplot.com/ ** +** Date: 21.03.14 ** +** Version: 1.2.0-beta ** +****************************************************************************/ + +#include "interaction-onebutton.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////// QCPAbstractInteractionOneButton +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*! \class QCPAbstractInteractionOneButton + \brief +*/ + +/* start documentation of inline functions */ + + +/* end documentation of inline functions */ + +QCPAbstractInteractionOneButton::QCPAbstractInteractionOneButton(QCustomPlot *parentPlot) : + QCPAbstractInteraction(parentPlot), + mButton(mbLeft), + mModifiers(Qt::NoModifier), + mButtonActive(), + mModifiersActive(false) +{ +} + +QCPAbstractInteractionOneButton::~QCPAbstractInteractionOneButton() +{ +} + +void QCPAbstractInteractionOneButton::mousePressEvent(QMouseEvent *event) +{ + if (toMouseButton(event->button()) == mButton && event->modifiers() == mModifiers) + buttonActivated(event); +} + +void QCPAbstractInteractionOneButton::mouseReleaseEvent(QMouseEvent *event) +{ + if (toMouseButton(event->button()) == mButton) + buttonDeactivated(event); +} diff --git a/src/interactions/interaction-onebutton.h b/src/interactions/interaction-onebutton.h new file mode 100644 index 00000000..838eb632 --- /dev/null +++ b/src/interactions/interaction-onebutton.h @@ -0,0 +1,76 @@ +/*************************************************************************** +** ** +** QCustomPlot, an easy to use, modern plotting widget for Qt ** +** Copyright (C) 2011, 2012, 2013, 2014 Emanuel Eichhammer ** +** ** +** This program is free software: you can redistribute it and/or modify ** +** it under the terms of the GNU General Public License as published by ** +** the Free Software Foundation, either version 3 of the License, or ** +** (at your option) any later version. ** +** ** +** This program is distributed in the hope that it will be useful, ** +** but WITHOUT ANY WARRANTY; without even the implied warranty of ** +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** +** GNU General Public License for more details. ** +** ** +** You should have received a copy of the GNU General Public License ** +** along with this program. If not, see http://www.gnu.org/licenses/. ** +** ** +**************************************************************************** +** Author: Erwan Mathieu ** +** Website/Contact: http://www.qcustomplot.com/ ** +** Date: 21.03.14 ** +** Version: 1.2.0-beta ** +****************************************************************************/ + +#ifndef QCP_ABSTRACTINTERACTION_ONEBUTTON +#define QCP_ABSTRACTINTERACTION_ONEBUTTON + +#include "../interaction.h" + + +class QCP_LIB_DECL QCPAbstractInteractionOneButton : public QCPAbstractInteraction +{ + Q_OBJECT + /// \cond INCLUDE_QPROPERTIES + Q_PROPERTY(QCPAbstractInteraction::MouseButton button READ button WRITE setButton) + Q_PROPERTY(Qt::KeyboardModifiers modifiers READ modifiers WRITE setModifiers) + /// \endcond +public: + QCPAbstractInteractionOneButton(QCustomPlot *parentPlot); + virtual ~QCPAbstractInteractionOneButton(); + + // getters: + MouseButton button() const { return mButton; } + Qt::KeyboardModifiers modifiers() { return mModifiers; } + + // setters: + void setButton(MouseButton button) { mButton = button; } + void setModifiers(Qt::KeyboardModifiers modifiers) { mModifiers = modifiers; } + +protected: + // property members: + MouseButton mButton; + Qt::KeyboardModifiers mModifiers; + + // non-property members + bool mButtonActive; + bool mModifiersActive; + bool mActive; + + // reimplemented virtual methods: + void mousePressEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + + // introduced virtual methods: + virtual void buttonActivated(QMouseEvent *event) = 0; + virtual void buttonDeactivated(QMouseEvent *event) = 0; + + // non-virtual methods: + void updateActive(QMouseEvent *event); + +private: + Q_DISABLE_COPY(QCPAbstractInteractionOneButton) +}; + +#endif // QCP_ABSTRACTINTERACTION_ONEBUTTON diff --git a/src/interactions/interaction-select.cpp b/src/interactions/interaction-select.cpp index c4022df4..5354e3f0 100644 --- a/src/interactions/interaction-select.cpp +++ b/src/interactions/interaction-select.cpp @@ -42,8 +42,7 @@ /* end documentation of inline functions */ QCPInteractionSelect::QCPInteractionSelect(QCustomPlot *parentPlot) : - QCPAbstractInteraction(parentPlot), - mButton(mbLeft), + QCPAbstractInteractionOneButton(parentPlot), mMultiSelectModifier(Qt::ControlModifier), mInteractions(0), mMousePressPos() @@ -69,50 +68,44 @@ void QCPInteractionSelect::setMultiSelectModifier(Qt::KeyboardModifier modifier) mMultiSelectModifier = modifier; } -void QCPInteractionSelect::mousePressEvent(QMouseEvent *event) +void QCPInteractionSelect::buttonActivated(QMouseEvent *event) { - if(toMouseButton(event->button()) == mButton) - { - mMousePressPos = event->pos(); - } + mMousePressPos = event->pos(); } -void QCPInteractionSelect::mouseReleaseEvent(QMouseEvent *event) +void QCPInteractionSelect::buttonDeactivated(QMouseEvent *event) { bool selectionStateChanged = false; - if(toMouseButton(event->button()) == mButton) + if ((mMousePressPos - event->pos()).manhattanLength() < 5) // determine whether it was a click operation { - if ((mMousePressPos - event->pos()).manhattanLength() < 5) // determine whether it was a click operation + QVariant details; + QCPLayerable *clickedLayerable = mParentPlot->layerableAt(event->pos(), true, &details); + bool additive = mInteractions.testFlag(QCP::iMultiSelect) && event->modifiers().testFlag(mMultiSelectModifier); + // deselect all other layerables if not additive selection: + if (!additive) { - QVariant details; - QCPLayerable *clickedLayerable = mParentPlot->layerableAt(event->pos(), true, &details); - bool additive = mInteractions.testFlag(QCP::iMultiSelect) && event->modifiers().testFlag(mMultiSelectModifier); - // deselect all other layerables if not additive selection: - if (!additive) + for (int i=0 ; ilayerCount() ; i++) + { + QCPLayer *layer = mParentPlot->layer(i); + + foreach (QCPLayerable *layerable, layer->children()) { - for(int i=0 ; ilayerCount() ; i++) + if (layerable != clickedLayerable && mInteractions.testFlag(layerable->selectionCategory())) { - QCPLayer *layer = mParentPlot->layer(i); - - foreach (QCPLayerable *layerable, layer->children()) - { - if (layerable != clickedLayerable && mInteractions.testFlag(layerable->selectionCategory())) - { - bool selChanged = false; - layerable->deselectEvent(&selChanged); - selectionStateChanged |= selChanged; - } - } + bool selChanged = false; + layerable->deselectEvent(&selChanged); + selectionStateChanged |= selChanged; } } - if (clickedLayerable && mInteractions.testFlag(clickedLayerable->selectionCategory())) - { - // a layerable was actually clicked, call its selectEvent: - bool selChanged = false; - clickedLayerable->selectEvent(event, additive, details, &selChanged); - selectionStateChanged |= selChanged; - } + } + } + if (clickedLayerable && mInteractions.testFlag(clickedLayerable->selectionCategory())) + { + // a layerable was actually clicked, call its selectEvent: + bool selChanged = false; + clickedLayerable->selectEvent(event, additive, details, &selChanged); + selectionStateChanged |= selChanged; } } diff --git a/src/interactions/interaction-select.h b/src/interactions/interaction-select.h index 1cdec133..f6607185 100644 --- a/src/interactions/interaction-select.h +++ b/src/interactions/interaction-select.h @@ -26,14 +26,13 @@ #ifndef QCP_INTERACTION_SELECT_H #define QCP_INTERACTION_SELECT_H -#include "../interaction.h" +#include "interaction-onebutton.h" -class QCP_LIB_DECL QCPInteractionSelect : public QCPAbstractInteraction +class QCP_LIB_DECL QCPInteractionSelect : public QCPAbstractInteractionOneButton { Q_OBJECT /// \cond INCLUDE_QPROPERTIES - Q_PROPERTY(QCPAbstractInteraction::MouseButton button READ button WRITE setButton) Q_PROPERTY(Qt::KeyboardModifier multiSelectModifier READ multiSelectModifier WRITE setMultiSelectModifier) /// \endcond public: @@ -41,25 +40,22 @@ public: virtual ~QCPInteractionSelect(); // getters: - MouseButton button() const { return mButton; } Qt::KeyboardModifier multiSelectModifier() const { return mMultiSelectModifier; } QCP::Interactions interactions() const { return mInteractions; } // setters: - void setButton(MouseButton button) { mButton = button; } void setMultiSelectModifier(Qt::KeyboardModifier modifier); void setInteractions(QCP::Interactions interactions) { mInteractions = interactions; } // reimplemented virtual method: - virtual void mousePressEvent(QMouseEvent *event); - virtual void mouseReleaseEvent(QMouseEvent *event); + virtual void buttonActivated(QMouseEvent *event); + virtual void buttonDeactivated(QMouseEvent *event); signals: void selectionChanged(); protected: // property members - MouseButton mButton; Qt::KeyboardModifier mMultiSelectModifier; QCP::Interactions mInteractions; diff --git a/src/interactions/interaction-zoomrect.cpp b/src/interactions/interaction-zoomrect.cpp index c0948721..f7142946 100644 --- a/src/interactions/interaction-zoomrect.cpp +++ b/src/interactions/interaction-zoomrect.cpp @@ -42,8 +42,7 @@ /* end documentation of inline functions */ QCPInteractionZoomRect::QCPInteractionZoomRect(QCustomPlot *parentPlot) : - QCPAbstractInteraction(parentPlot), - mButton(mbLeft), + QCPAbstractInteractionOneButton(parentPlot), mAxis(), mMousePressPos(), mRubberBand(new QRubberBand(QRubberBand::Rectangle, parentPlot)) @@ -55,9 +54,9 @@ QCPInteractionZoomRect::~QCPInteractionZoomRect() { } -void QCPInteractionZoomRect::mousePressEvent(QMouseEvent *event) +void QCPInteractionZoomRect::buttonActivated(QMouseEvent *event) { - if(toMouseButton(event->button()) == mButton && not mAxis.isEmpty()) + if (not mAxis.isEmpty()) { mMousePressPos = event->pos(); mRubberBand->setGeometry(QRect(mMousePressPos, QSize(0, 0))); @@ -67,27 +66,30 @@ void QCPInteractionZoomRect::mousePressEvent(QMouseEvent *event) void QCPInteractionZoomRect::mouseMoveEvent(QMouseEvent *event) { - if(mRubberBand->isVisible()) + if (mRubberBand->isVisible()) mRubberBand->setGeometry(QRect(mMousePressPos, event->pos()).normalized()); + + QCPAbstractInteractionOneButton::mouseMoveEvent(event); } -void QCPInteractionZoomRect::mouseReleaseEvent(QMouseEvent *event) +void QCPInteractionZoomRect::buttonDeactivated(QMouseEvent *event) { + Q_UNUSED(event) bool ranged = false; - if(toMouseButton(event->button()) == mButton && mRubberBand->isVisible()) + if (mRubberBand->isVisible()) { mRubberBand->hide(); QRect rect = mRubberBand->geometry(); - if(rect.width() > 10 && rect.height() > 10) // protection against unvolotary moves + if (rect.width() > 10 && rect.height() > 10) // protection against unvolotary moves { - foreach(QPointer axis, mAxis) + foreach (QPointer axis, mAxis) { - if(not axis.isNull()) + if (not axis.isNull()) { double lower; double upper; - if(axis->axisType() == QCPAxis::atLeft || axis->axisType() == QCPAxis::atRight) + if (axis->axisType() == QCPAxis::atLeft || axis->axisType() == QCPAxis::atRight) { // vertical axis, take the rect height lower = axis->pixelToCoord(rect.bottom()); @@ -107,6 +109,6 @@ void QCPInteractionZoomRect::mouseReleaseEvent(QMouseEvent *event) } } - if(ranged) + if (ranged) mParentPlot->replot(); } diff --git a/src/interactions/interaction-zoomrect.h b/src/interactions/interaction-zoomrect.h index 16ad3be5..08609004 100644 --- a/src/interactions/interaction-zoomrect.h +++ b/src/interactions/interaction-zoomrect.h @@ -26,40 +26,34 @@ #ifndef QCP_INTERACTION_ZOOMRECT_H #define QCP_INTERACTION_ZOOMRECT_H -#include "../interaction.h" +#include "interaction-onebutton.h" class QRubberBand; class QCPAxis; -class QCP_LIB_DECL QCPInteractionZoomRect : public QCPAbstractInteraction +class QCP_LIB_DECL QCPInteractionZoomRect : public QCPAbstractInteractionOneButton { Q_OBJECT - /// \cond INCLUDE_QPROPERTIES - Q_PROPERTY(QCPAbstractInteraction::MouseButton button READ button WRITE setButton) - /// \endcond public: QCPInteractionZoomRect(QCustomPlot *parentPlot); virtual ~QCPInteractionZoomRect(); // getters: - MouseButton button() const { return mButton; } int axisCount() const { return mAxis.count(); } QCPAxis *axis(int index) const { return mAxis[index]; } // setters: - void setButton(MouseButton button) { mButton = button; } void clearAxis() { mAxis.clear(); } void addAxis(QCPAxis *axis) { mAxis << axis; } // reimplemented virtual method: - virtual void mousePressEvent(QMouseEvent *event); + virtual void buttonActivated(QMouseEvent *event); virtual void mouseMoveEvent(QMouseEvent *event); - virtual void mouseReleaseEvent(QMouseEvent *event); + virtual void buttonDeactivated(QMouseEvent *event); protected: // property members - MouseButton mButton; QList > mAxis; // non-property members diff --git a/src/qcustomplot.cpp.skeleton b/src/qcustomplot.cpp.skeleton index 1bf624ad..df8e5514 100644 --- a/src/qcustomplot.cpp.skeleton +++ b/src/qcustomplot.cpp.skeleton @@ -56,6 +56,7 @@ //amalgamation: add items/item-pixmap.cpp //amalgamation: add items/item-tracer.cpp //amalgamation: add items/item-bracket.cpp +//amalgamation: add interactions/interaction-onebutton.cpp //amalgamation: add interactions/interaction-dragrange.cpp //amalgamation: add interactions/interaction-select.cpp //amalgamation: add interactions/interaction-zoomrange.cpp diff --git a/src/qcustomplot.h.skeleton b/src/qcustomplot.h.skeleton index fc9e3277..c4939f65 100644 --- a/src/qcustomplot.h.skeleton +++ b/src/qcustomplot.h.skeleton @@ -59,6 +59,7 @@ //amalgamation: add items/item-pixmap.h //amalgamation: add items/item-tracer.h //amalgamation: add items/item-bracket.h +//amalgamation: add interactions/interaction-onebutton.h //amalgamation: add interactions/interaction-dragrange.h //amalgamation: add interactions/interaction-select.h //amalgamation: add interactions/interaction-zoomrange.h -- GitLab From f714defa3e3ef7fa699d2dd0ee56042674d80d51 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 21 Mar 2014 16:33:19 +0100 Subject: [PATCH 08/10] Modified staticlib project file to include interactions --- src/qcp-staticlib.pro | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/qcp-staticlib.pro b/src/qcp-staticlib.pro index 8ad0a2e5..c016bab6 100644 --- a/src/qcp-staticlib.pro +++ b/src/qcp-staticlib.pro @@ -55,7 +55,13 @@ layoutelements/layoutelement-axisrect.h \ layoutelements/layoutelement-legend.h \ layoutelements/layoutelement-plottitle.h \ layoutelements/layoutelement-colorscale.h \ - colorgradient.h + colorgradient.h \ + interaction.h \ + interactions/interaction-zoomrange.h \ + interactions/interaction-zoomrect.h \ + interactions/interaction-dragrange.h \ + interactions/interaction-select.h \ + interactions/interaction-onebutton.h SOURCES += \ painter.cpp \ @@ -85,7 +91,13 @@ layoutelements/layoutelement-axisrect.cpp \ layoutelements/layoutelement-legend.cpp \ layoutelements/layoutelement-plottitle.cpp \ layoutelements/layoutelement-colorscale.cpp \ - colorgradient.cpp + colorgradient.cpp \ + interaction.cpp \ + interactions/interaction-zoomrange.cpp \ + interactions/interaction-zoomrect.cpp \ + interactions/interaction-dragrange.cpp \ + interactions/interaction-select.cpp \ + interactions/interaction-onebutton.cpp OTHER_FILES += \ ../changelog.txt \ -- GitLab From 7779e32da363edab261d26f4c805f04267e0222c Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 21 Mar 2014 16:44:28 +0100 Subject: [PATCH 09/10] Interactions can now be activated/deactivated individually --- src/core.cpp | 24 +++++++++++++++++------- src/interaction.cpp | 2 +- src/interaction.h | 8 +++----- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/core.cpp b/src/core.cpp index 7fa7be08..39e95186 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -2313,6 +2313,12 @@ void QCustomPlot::mouseDoubleClickEvent(QMouseEvent *event) mMouseEventElement->mouseReleaseEvent(event); mMouseEventElement = 0; } + + foreach(QCPAbstractInteraction *interaction, mInteractions) + { + if (interaction->active()) + interaction->mouseDoubleClickEvent(event); + } //QWidget::mouseDoubleClickEvent(event); don't call base class implementation because it would just cause a mousePress/ReleaseEvent, which we don't want. } @@ -2335,9 +2341,10 @@ void QCustomPlot::mousePressEvent(QMouseEvent *event) if (mMouseEventElement) mMouseEventElement->mousePressEvent(event); - foreach(QCPAbstractInteraction *interaction, mInteractions) + foreach (QCPAbstractInteraction *interaction, mInteractions) { - interaction->mousePressEvent(event); + if(interaction->active()) + interaction->mousePressEvent(event); } QWidget::mousePressEvent(event); @@ -2360,9 +2367,10 @@ void QCustomPlot::mouseMoveEvent(QMouseEvent *event) if (mMouseEventElement) mMouseEventElement->mouseMoveEvent(event); - foreach(QCPAbstractInteraction *interaction, mInteractions) + foreach (QCPAbstractInteraction *interaction, mInteractions) { - interaction->mouseMoveEvent(event); + if (interaction->active()) + interaction->mouseMoveEvent(event); } QWidget::mouseMoveEvent(event); @@ -2412,9 +2420,10 @@ void QCustomPlot::mouseReleaseEvent(QMouseEvent *event) mMouseEventElement = 0; } - foreach(QCPAbstractInteraction *interaction, mInteractions) + foreach (QCPAbstractInteraction *interaction, mInteractions) { - interaction->mouseReleaseEvent(event); + if (interaction->active()) + interaction->mouseReleaseEvent(event); } QWidget::mouseReleaseEvent(event); @@ -2436,7 +2445,8 @@ void QCustomPlot::wheelEvent(QWheelEvent *event) foreach(QCPAbstractInteraction *interaction, mInteractions) { - interaction->mouseWheelEvent(event); + if (interaction->active()) + interaction->mouseWheelEvent(event); } QWidget::wheelEvent(event); diff --git a/src/interaction.cpp b/src/interaction.cpp index c74f8668..0739e37a 100644 --- a/src/interaction.cpp +++ b/src/interaction.cpp @@ -38,7 +38,7 @@ QCPAbstractInteraction::QCPAbstractInteraction(QCustomPlot *parentPlot) : QObject(parentPlot), mParentPlot(parentPlot), - mActive(false) + mActive(true) { } diff --git a/src/interaction.h b/src/interaction.h index 76f36226..ad19372b 100644 --- a/src/interaction.h +++ b/src/interaction.h @@ -38,14 +38,14 @@ class QCP_LIB_DECL QCPAbstractInteraction : public QObject Q_OBJECT public: /*! - Defines the pressed mouse buttons + Defines the mouse buttons which may be pressed/released/triggered */ enum MouseButton { mbNone ///< No button ,mbLeft ///< The mouse standard left button ,mbRight ///< The mouse standard right button ,mbMiddle ///< The mouse middle button, usually triggered by pressing the wheel - ,mbWheelUp ///< Pseudo-button, use when the wheel has been moved up - ,mbWheelDown ///< Pseudo-button, use when the wheel has been moved down + ,mbWheelUp ///< Pseudo-button, triggered when the wheel has been moved up + ,mbWheelDown ///< Pseudo-button, triggered when the wheel has been moved down ,mbXButton1 ///< First optional mouse button, usually located on the side ,mbXButton2 ///< Seconcd optional mouse button, usually located on the side }; @@ -66,8 +66,6 @@ public: virtual void mouseMoveEvent(QMouseEvent *event) { Q_UNUSED(event); } virtual void mouseReleaseEvent(QMouseEvent *event) { Q_UNUSED(event); } virtual void mouseWheelEvent(QWheelEvent *event) { Q_UNUSED(event); } - virtual void keyPressEvent(QKeyEvent *event) { Q_UNUSED(event); } - virtual void keyReleaseEvent(QKeyEvent *event) { Q_UNUSED(event); } // static methods: MouseButton toMouseButton(Qt::MouseButton button); -- GitLab From 838a19f480f7c54d6e31ed3191d8e12cd7f24ebd Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 24 Mar 2014 10:45:46 +0100 Subject: [PATCH 10/10] Code documentation and polishing --- src/core.cpp | 4 +- src/interaction.cpp | 37 ++++++- src/interaction.h | 4 +- src/interactions/interaction-dragrange.cpp | 24 +++-- src/interactions/interaction-dragrange.h | 1 - src/interactions/interaction-onebutton.cpp | 32 +++++- src/interactions/interaction-onebutton.h | 2 - src/interactions/interaction-select.cpp | 20 +++- src/interactions/interaction-zoomrange.cpp | 120 ++++++++++----------- src/interactions/interaction-zoomrect.cpp | 20 +++- 10 files changed, 171 insertions(+), 93 deletions(-) diff --git a/src/core.cpp b/src/core.cpp index 39e95186..ee47b556 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -845,7 +845,7 @@ void QCustomPlot::setInteractions(const QCP::Interactions &interactions) interaction->addAxis(yAxis); mInteractions << interaction; } - else if(not interactions.testFlag(QCP::iRangeZoom) && interactionZoomRange) + else if(!interactions.testFlag(QCP::iRangeZoom) && interactionZoomRange) { delete interactionZoomRange; mInteractions.removeAll(interactionZoomRange); @@ -859,7 +859,7 @@ void QCustomPlot::setInteractions(const QCP::Interactions &interactions) interaction->addAxis(yAxis); mInteractions << interaction; } - else if(not interactions.testFlag(QCP::iRectZoom) && interactionRectZoom) + else if(!interactions.testFlag(QCP::iRectZoom) && interactionRectZoom) { delete interactionRectZoom; mInteractions.removeAll(interactionRectZoom); diff --git a/src/interaction.cpp b/src/interaction.cpp index 0739e37a..482eedaf 100644 --- a/src/interaction.cpp +++ b/src/interaction.cpp @@ -32,9 +32,37 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPAbstractInteraction - \brief + \brief Base class for user interactions + + An interaction is basically the user pressing the mouse over the plot, moving it around, + and releasing the button. According to the implementation, the interaction may select a curve, + zoom in/out, translate the axis, ... + + Standard interactions can be activated/deactivated using \ref QCustomPlot::setInteractions. They + will use the most common buttons, and no keyboard modifiers, to suit usual needs. If you want to + customize an interaction, retrieve it using \ref QCustomPlot::interaction and call its specific + methods. + + Each interaction can be individually activated or deactived by calling \ref setActive. When an + interaction is inactive, it is ignored by the parent plot which does not call the event methods. + This is useful to activate/deactive interactions without destroying/recreating them. + + This class is an abstract placeholder for all interactions. To add you own custom interactions, + override it and call \ref QCustomPlot::addInteraction to make it fully active. + + When using many interactions at the same time, you should take care that they don't activate + together. For example, if you set a drag range and a zoom rect interaction both on the left mouse + button, this is going to do weird things, because each will catch the mouse events and to their + job. However, you can use a select and a zoom rect interaction on the left button, because + selection works on a single point click and zoom rect uses a mouse mouse : the select will + activate only if the cursor didn't move between click and release, and the zoom will activate only + if the cursor relevantly moved between click and release. To avoid bad cases, you can also use + keyboard modifiers. */ +/*! + Creates a new QCPAbstractInteraction. This constructor is to be used by child classes only. +*/ QCPAbstractInteraction::QCPAbstractInteraction(QCustomPlot *parentPlot) : QObject(parentPlot), mParentPlot(parentPlot), @@ -46,9 +74,14 @@ QCPAbstractInteraction::~QCPAbstractInteraction() { } +/*! + Converts the Qt::MouseButton retrieved on the QMouseEvent to a QCP MouseButton enumeration. + This is required to ease the configuration of interactions by including the wheel into the + enumeration, as if it were just two standard buttons. +*/ QCPAbstractInteraction::MouseButton QCPAbstractInteraction::toMouseButton(Qt::MouseButton button) { - switch(button) + switch (button) { case Qt::LeftButton: return mbLeft; diff --git a/src/interaction.h b/src/interaction.h index ad19372b..5c4e5cc7 100644 --- a/src/interaction.h +++ b/src/interaction.h @@ -32,10 +32,12 @@ class QCustomPlot; - class QCP_LIB_DECL QCPAbstractInteraction : public QObject { Q_OBJECT + /// \cond INCLUDE_QPROPERTIES + Q_PROPERTY(bool active READ active WRITE setActive) + /// \endcond public: /*! Defines the mouse buttons which may be pressed/released/triggered diff --git a/src/interactions/interaction-dragrange.cpp b/src/interactions/interaction-dragrange.cpp index d7c33e02..8d448272 100644 --- a/src/interactions/interaction-dragrange.cpp +++ b/src/interactions/interaction-dragrange.cpp @@ -33,13 +33,17 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPInteractionDragRange - \brief -*/ - -/* start documentation of inline functions */ + \brief Interaction to drag the plot ranges with the mouse + This interaction works very naturally : the user presses a mouse button over the plot, moves the + cursor around, which moves the axis ranges accordingly, and it stops when the mouse button + is released. You can also set keyboard modifiers to trigger the drag only when some buttons are + pressed. -/* end documentation of inline functions */ + To fully activate the interaction, you need to set the dragged axis by calling \ref addAxis. The + standard case is to drag the first X and Y axis, but you can decide to drag only the X axis if you + have a fixed Y range, or drag the secondary X and Y axis at the same time. +*/ QCPInteractionDragRange::QCPInteractionDragRange(QCustomPlot *parentPlot) : QCPAbstractInteractionOneButton(parentPlot), @@ -68,7 +72,7 @@ void QCPInteractionDragRange::setNoAntialiasingOnDrag(bool enabled) void QCPInteractionDragRange::buttonActivated(QMouseEvent *event) { - if (not mAxis.isEmpty()) + if (!mAxis.isEmpty()) { mMousePressPos = event->pos(); @@ -82,7 +86,7 @@ void QCPInteractionDragRange::buttonActivated(QMouseEvent *event) mRangesStart.clear(); foreach (QPointer axis, mAxis) { - if (not axis.isNull()) + if (!axis.isNull()) { mRangesStart << axis->range(); } @@ -94,12 +98,12 @@ void QCPInteractionDragRange::mouseMoveEvent(QMouseEvent *event) { bool ranged = false; - if (not mMousePressPos.isNull()) + if (!mMousePressPos.isNull()) { int i=0; foreach (QPointer axis, mAxis) { - if (not axis.isNull()) + if (!axis.isNull()) { QCPRange rangeStart = mRangesStart[i++]; int dragStart, mousePos; @@ -145,7 +149,7 @@ void QCPInteractionDragRange::mouseMoveEvent(QMouseEvent *event) void QCPInteractionDragRange::buttonDeactivated(QMouseEvent *event) { Q_UNUSED(event) - if (not mMousePressPos.isNull()) + if (!mMousePressPos.isNull()) { mMousePressPos = QPoint(); if (mNoAntialiasingOnDrag) diff --git a/src/interactions/interaction-dragrange.h b/src/interactions/interaction-dragrange.h index effd2395..44bbf190 100644 --- a/src/interactions/interaction-dragrange.h +++ b/src/interactions/interaction-dragrange.h @@ -30,7 +30,6 @@ class QCPAxis; - class QCP_LIB_DECL QCPInteractionDragRange : public QCPAbstractInteractionOneButton { Q_OBJECT diff --git a/src/interactions/interaction-onebutton.cpp b/src/interactions/interaction-onebutton.cpp index 162d589c..69fe0fd1 100644 --- a/src/interactions/interaction-onebutton.cpp +++ b/src/interactions/interaction-onebutton.cpp @@ -30,11 +30,30 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPAbstractInteractionOneButton - \brief + \brief Base class for interactions which are based on a single mouse button + + This class is provided for convenience, because many interactions work by using a single mouse + button, and keyboard modifiers. The button and the modifiers can be customized easily, so that the + final application suits the user at best. + + The interaction starts when the mouse button is pressed, and only if the pressed modifiers match + the set modifiers at this very moment. It lasts until the mouse button is released, even if the + keyboard modifiers are released in the meantime. This is the most natural way to do things. */ /* start documentation of inline functions */ +/*! \fn virtual void buttonActivated(QMouseEvent *event) + + Virtual method called when the mouse button is pressed and the pressed keyboard modifiers match + the set modifiers. The real interaction job should start there. +*/ + +/*! \fn virtual void buttonDeactivated(QMouseEvent *event) + + Virtual method called when the mouse button is released and the interaction is currently active. + The real interaction job should stop here. +*/ /* end documentation of inline functions */ @@ -42,8 +61,7 @@ QCPAbstractInteractionOneButton::QCPAbstractInteractionOneButton(QCustomPlot *pa QCPAbstractInteraction(parentPlot), mButton(mbLeft), mModifiers(Qt::NoModifier), - mButtonActive(), - mModifiersActive(false) + mActive(false) { } @@ -54,11 +72,17 @@ QCPAbstractInteractionOneButton::~QCPAbstractInteractionOneButton() void QCPAbstractInteractionOneButton::mousePressEvent(QMouseEvent *event) { if (toMouseButton(event->button()) == mButton && event->modifiers() == mModifiers) + { + mActive = true; buttonActivated(event); + } } void QCPAbstractInteractionOneButton::mouseReleaseEvent(QMouseEvent *event) { - if (toMouseButton(event->button()) == mButton) + if (mActive && toMouseButton(event->button()) == mButton) + { + mActive = false; buttonDeactivated(event); + } } diff --git a/src/interactions/interaction-onebutton.h b/src/interactions/interaction-onebutton.h index 838eb632..9314ae9d 100644 --- a/src/interactions/interaction-onebutton.h +++ b/src/interactions/interaction-onebutton.h @@ -54,8 +54,6 @@ protected: Qt::KeyboardModifiers mModifiers; // non-property members - bool mButtonActive; - bool mModifiersActive; bool mActive; // reimplemented virtual methods: diff --git a/src/interactions/interaction-select.cpp b/src/interactions/interaction-select.cpp index 5354e3f0..a1cff642 100644 --- a/src/interactions/interaction-select.cpp +++ b/src/interactions/interaction-select.cpp @@ -33,11 +33,27 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPInteractionSelect - \brief + \brief Interaction which lets the user select one or more elements of the plot + + This interaction is quite simple as it only manages the user mouse click and calls the + \ref selectEvent or \ref deselectEvent of the appropriate elements. When the selection changes in + any way, the \ref selectionChanged signal is emitted. + + The \ref setInteractions methods lets you customise which elements of the plot are to be selected, + and whether many elements may be selected at the same time. */ /* start documentation of inline functions */ +/*! \fn void setInteractions(QCP::Interactions interactions) + + This methods allows you to configure which elements of the plot may be selected through this + interaction. You can combine whichever elements you want using the Interactions flags. Of course, + only the iSelect* values of the enumeration are considered. + + You can also set the iMultiSelect flag to indicate that the user may select many elements + simultaneously. +*/ /* end documentation of inline functions */ @@ -60,8 +76,6 @@ QCPInteractionSelect::~QCPInteractionSelect() by clicking on them one after the other while holding down \a modifier. By default the multi-select-modifier is set to Qt::ControlModifier. - - \see setInteractions */ void QCPInteractionSelect::setMultiSelectModifier(Qt::KeyboardModifier modifier) { diff --git a/src/interactions/interaction-zoomrange.cpp b/src/interactions/interaction-zoomrange.cpp index 07cab6b9..933942a1 100644 --- a/src/interactions/interaction-zoomrange.cpp +++ b/src/interactions/interaction-zoomrange.cpp @@ -33,65 +33,29 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPInteractionZoomRange - \brief Interaction for mouse zoom in/out using the wheel or buttons. If orientations is - Qt::Horizontal, Qt::Vertical or both, the ranges of the defined axes are scaled. The center of - the scaling operation is the current cursor position inside the axis rect. The scaling factor is - dependant on the mouse wheel delta (which direction the wheel was rotated) to provide a natural - zooming feel. The Strength of the zoom can be controlled via \ref setFactor. To zoom in/out using - other mouse buttons, you may call the \ref setButtonZoomIn and \ref setButtonZoomOut methods. + \brief Interaction for mouse zoom in/out using the wheel or buttons. - Note, that event->delta() is usually +/-120 for single rotation steps. However, if the mouse - wheel is turned rapidly, many steps may bunch up to one event, so the event->delta() may then be - multiples of 120. This is taken into account here, by calculating \a wheelSteps and using it as - exponent of the range zoom factor. This takes care of the wheel direction automatically, by - inverting the factor, when the wheel step is negative (f^-1 = 1/f). + The axis to be zoomed in/out are to be set using the \ref addAxis method. If no axis is set, the + interaction will do nothing. If many axis are set, they will all be zoomed when the interacton is + triggered. The center of the scaling operation is the current cursor position inside the axis + rect. The strength of the zoom can be controlled for each axis when adding them. However, using + different factors for each axis may be disturbing unless you have a very specific application. */ /* start documentation of inline functions */ -/*! \fn void QCPInteractionZoomRange::setOrientations(Qt::Orientations orientations) - - Sets which axis orientation may be zoomed by the user with the mouse wheel. What orientation - corresponds to which specific axis can be set with \ref setRangeZoomAxes(QCPAxis *horizontal, - QCPAxis *vertical). By default, the horizontal axis is the bottom axis (xAxis) and the vertical - axis is the left axis (yAxis). - - To disable range zooming entirely, pass 0 as \a orientations or remove \ref QCP::iRangeZoom from \ref - QCustomPlot::setInteractions. To enable range zooming for both directions, pass Qt::Horizontal | - Qt::Vertical as \a orientations. - - In addition to setting \a orientations to a non-zero value, make sure \ref QCustomPlot::setInteractions - contains \ref QCP::iRangeZoom to enable the range zooming interaction. - - \see setRangeZoomFactor, setRangeZoomAxes, setRangeDrag -*/ - -/*! \fn void QCPInteractionZoomRange::setFactorHorz(double factor) - - Sets how strong step of the mouse button zooms in/out on the horizontal axis. The two methods - \a setFactorHorz and \a setFactorVert provide a way to let the horizontal axis zoom at different - rates than the vertical axis. Which axis is horizontal and which is vertical, can be set - with \ref setAxes. - - \see setFactorVert, setFactor -*/ - -/*! \fn void QCPInteractionZoomRange::setFactorVert(double factor) - - Sets how strong step of the mouse button zooms in/out on the vertical axis. The two methods - \a setFactorHorz and \a setFactorVert provide a way to let the horizontal axis zoom at different - rates than the vertical axis. Which axis is horizontal and which is vertical, can be set - with \ref setAxes. - - \see setFactorHorz, setFactor -*/ +/*! \fn void addAxis(QCPAxis *axis, double factor) -/*! \fn void QCPInteractionZoomRange::setFactor(double factor) + Adds an axis to be zoomed by the user with the mouse. Once the axis has been added, its range will + be scaled each time the interaction is triggered. By default, the interactions contains no axis, + making it useless. - Sets how strong step of the mouse button zooms in/out on both the horizontal and vertical axis. - The \a factor should be lesser than 1, or the zoom will be inverted. + You can add as many axis as wanted, they will all be treated independantly. - \see setFactorHorz, setFactorVert + The \a factor indicates how strong the zoom is. The default value makes a natural zoom, but you can + increase it if your application requires that you move very quickly from a large view to a small + view. Or you can decrease it if you need to set a very specific zoom level. The factor should be + lesser than 1, or the zoom will be inverted. */ /* end documentation of inline functions */ @@ -109,10 +73,19 @@ QCPInteractionZoomRange::~QCPInteractionZoomRange() { } +/*! + Function provided for convience : it sets the zoom factor for each registered axis, which is the + most common case. + + The \a factor indicates how strong the zoom is. The default value makes a natural zoom, but you can + increase it if your application requires that you move very quickly from a large view to a small + view. Or you can decrease it if you need to set a very specific zoom level. The factor should be + lesser than 1, or the zoom will be inverted. +*/ void QCPInteractionZoomRange::setFactor(double factor) { QMutableListIterator, double> > iterator(mAxis); - while(iterator.hasNext()) + while (iterator.hasNext()) { iterator.next().second = factor; } @@ -121,7 +94,7 @@ void QCPInteractionZoomRange::setFactor(double factor) void QCPInteractionZoomRange::mousePressEvent(QMouseEvent *event) { MouseButton button = toMouseButton(event->button()); - if(button == mButtonZoomIn || button == mButtonZoomOut) + if (button == mButtonZoomIn || button == mButtonZoomOut) { mMousePressPos = event->pos(); } @@ -130,7 +103,7 @@ void QCPInteractionZoomRange::mousePressEvent(QMouseEvent *event) void QCPInteractionZoomRange::mouseReleaseEvent(QMouseEvent *event) { MouseButton button = toMouseButton(event->button()); - if(button == mButtonZoomIn || button == mButtonZoomOut) + if (button == mButtonZoomIn || button == mButtonZoomOut) { if ((mMousePressPos - event->pos()).manhattanLength() < 5) // determine whether it was a click operation { @@ -139,41 +112,60 @@ void QCPInteractionZoomRange::mouseReleaseEvent(QMouseEvent *event) } } +/*! \internal + \brief Method called when the mouse wheel has been rotated up or down. + + Note, that event->delta() is usually +/-120 for single rotation steps. However, if the mouse + wheel is turned rapidly, many steps may bunch up to one event, so the event->delta() may then be + multiples of 120. This is taken into account here, by calculating \a wheelSteps and using it as + exponent of the range zoom factor. This takes care of the wheel direction automatically, by + inverting the factor, when the wheel step is negative (f^-1 = 1/f). + */ void QCPInteractionZoomRange::mouseWheelEvent(QWheelEvent *event) { double wheelDelta = event->delta() / 120.0; // a single step delta is +/-120 usually double wise = 0; - if(wheelDelta > 0) + if (wheelDelta > 0) { - if(mButtonZoomIn == mbWheelUp) + if (mButtonZoomIn == mbWheelUp) wise = 1; - else if(mButtonZoomOut == mbWheelUp) + else if (mButtonZoomOut == mbWheelUp) wise = -1; } else { - if(mButtonZoomIn == mbWheelDown) + if (mButtonZoomIn == mbWheelDown) wise = -1; - else if(mButtonZoomOut == mbWheelDown) + else if (mButtonZoomOut == mbWheelDown) wise = 1; } - if(!qFuzzyIsNull(wise)) + if (!qFuzzyIsNull(wise)) doZoom(event->pos(), wheelDelta * wise); } +/*! \internal + \brief Actually compute the range zoom + + This method computes and applies the new ranges for each registered axis, according to the given + zoom parameters. + + The \a pos is the current mouse position, used to zoom on a specific zone on the graph. + The \a steps indicates how strong the zoom should be made. It may be negative to indicate + a zoom out. + */ void QCPInteractionZoomRange::doZoom(const QPoint &pos, double steps) { bool scaled = false; - for(int i=0 ; i axis = mAxis[i].first; - if(not axis.isNull()) + if (!axis.isNull()) { int mousePos; - if(axis->axisType() == QCPAxis::atLeft || axis->axisType() == QCPAxis::atRight) + if (axis->axisType() == QCPAxis::atLeft || axis->axisType() == QCPAxis::atRight) { // vertical axis, take the y position of the mouse mousePos = pos.y(); @@ -189,6 +181,6 @@ void QCPInteractionZoomRange::doZoom(const QPoint &pos, double steps) } } - if(scaled) + if (scaled) parentPlot()->replot(); } diff --git a/src/interactions/interaction-zoomrect.cpp b/src/interactions/interaction-zoomrect.cpp index f7142946..c8072ae6 100644 --- a/src/interactions/interaction-zoomrect.cpp +++ b/src/interactions/interaction-zoomrect.cpp @@ -33,7 +33,19 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPInteractionZoomRect - \brief + \brief Interaction for zooming on a specific area by drawing a rectangle around it. + + This interaction works in 3 steps : the user cliks on the plot, then moves the mouse around which + draws a selection rectangle (a QRubberBand), then the mouse button is released. At this time, + the drawn rectangle is considered to be the new axis ranges. This allows to move quickly from a + graph containing many data to an area containing interesting information. It also offers the + ability to zoom separately on the X and Y axis, so that the displayed data may be more relevant. + + To make this interaction fully working, you need to call the \ref addAxis method as many times as + required to insert all the axis you want to be zoomed. + + This interaction only allows for zoom in. If you need to zoom out, use it in parallel with an + other interaction like zoom range, or add an external button to set the axes ranges manually. */ /* start documentation of inline functions */ @@ -56,7 +68,7 @@ QCPInteractionZoomRect::~QCPInteractionZoomRect() void QCPInteractionZoomRect::buttonActivated(QMouseEvent *event) { - if (not mAxis.isEmpty()) + if (!mAxis.isEmpty()) { mMousePressPos = event->pos(); mRubberBand->setGeometry(QRect(mMousePressPos, QSize(0, 0))); @@ -80,11 +92,11 @@ void QCPInteractionZoomRect::buttonDeactivated(QMouseEvent *event) { mRubberBand->hide(); QRect rect = mRubberBand->geometry(); - if (rect.width() > 10 && rect.height() > 10) // protection against unvolotary moves + if (rect.width() > 10 && rect.height() > 10) // protection against involoutary moves { foreach (QPointer axis, mAxis) { - if (not axis.isNull()) + if (!axis.isNull()) { double lower; double upper; -- GitLab