diff --git a/src/chartdataset.cpp b/src/chartdataset.cpp index 4d7e1a0..a3bf5a4 100644 --- a/src/chartdataset.cpp +++ b/src/chartdataset.cpp @@ -445,6 +445,31 @@ void ChartDataSet::zoomOutDomain(const QRectF &rect) domain->blockRangeSignals(false); } +void ChartDataSet::zoomResetDomain() +{ + QList domains; + foreach (QAbstractSeries *s, m_seriesList) { + AbstractDomain *domain = s->d_ptr->domain(); + s->d_ptr->m_domain->blockRangeSignals(true); + domains << domain; + } + + foreach (AbstractDomain *domain, domains) + domain->zoomReset(); + + foreach (AbstractDomain *domain, domains) + domain->blockRangeSignals(false); +} + +bool ChartDataSet::isZoomedDomain() +{ + foreach (QAbstractSeries *s, m_seriesList) { + if (s->d_ptr->domain()->isZoomed()) + return true; + } + return false; +} + void ChartDataSet::scrollDomain(qreal dx, qreal dy) { QList domains; diff --git a/src/chartdataset_p.h b/src/chartdataset_p.h index 3305c68..442cc6b 100644 --- a/src/chartdataset_p.h +++ b/src/chartdataset_p.h @@ -62,6 +62,8 @@ public: void zoomInDomain(const QRectF &rect); void zoomOutDomain(const QRectF &rect); + void zoomResetDomain(); + bool isZoomedDomain(); void scrollDomain(qreal dx, qreal dy); QPointF mapToValue(const QPointF &position, QAbstractSeries *series = 0); diff --git a/src/domain/abstractdomain.cpp b/src/domain/abstractdomain.cpp index 277472d..f5ec9f4 100644 --- a/src/domain/abstractdomain.cpp +++ b/src/domain/abstractdomain.cpp @@ -30,7 +30,13 @@ AbstractDomain::AbstractDomain(QObject *parent) m_maxX(0), m_minY(0), m_maxY(0), - m_signalsBlocked(false) + m_signalsBlocked(false), + m_zoomed(false), + m_zoomResetMinX(0), + m_zoomResetMaxX(0), + m_zoomResetMinY(0), + m_zoomResetMaxY(0) + { } @@ -131,6 +137,28 @@ void AbstractDomain::blockRangeSignals(bool block) } } +void AbstractDomain::zoomReset() +{ + if (m_zoomed) { + setRange(m_zoomResetMinX, + m_zoomResetMaxX, + m_zoomResetMinY, + m_zoomResetMaxY); + m_zoomed = false; + } +} + +void AbstractDomain::storeZoomReset() +{ + if (!m_zoomed) { + m_zoomed = true; + m_zoomResetMinX = m_minX; + m_zoomResetMaxX = m_maxX; + m_zoomResetMinY = m_minY; + m_zoomResetMaxY = m_maxY; + } +} + //algorithm defined by Paul S.Heckbert GraphicalGems I void AbstractDomain::looseNiceNumbers(qreal &min, qreal &max, int &ticksCount) diff --git a/src/domain/abstractdomain_p.h b/src/domain/abstractdomain_p.h index cf7c2ba..19c82fe 100644 --- a/src/domain/abstractdomain_p.h +++ b/src/domain/abstractdomain_p.h @@ -80,6 +80,10 @@ public: void blockRangeSignals(bool block); bool rangeSignalsBlocked() const { return m_signalsBlocked; } + void zoomReset(); + void storeZoomReset(); + bool isZoomed() { return m_zoomed; } + friend bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const AbstractDomain &domain1, const AbstractDomain &domain2); friend bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator!= (const AbstractDomain &domain1, const AbstractDomain &domain2); friend QDebug QTCOMMERCIALCHART_AUTOTEST_EXPORT operator<<(QDebug dbg, const AbstractDomain &domain); @@ -116,6 +120,11 @@ protected: qreal m_maxY; QSizeF m_size; bool m_signalsBlocked; + bool m_zoomed; + qreal m_zoomResetMinX; + qreal m_zoomResetMaxX; + qreal m_zoomResetMinY; + qreal m_zoomResetMaxY; }; QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/domain/logxlogydomain.cpp b/src/domain/logxlogydomain.cpp index adb9bc1..3732bbf 100644 --- a/src/domain/logxlogydomain.cpp +++ b/src/domain/logxlogydomain.cpp @@ -78,6 +78,7 @@ void LogXLogYDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY) void LogXLogYDomain::zoomIn(const QRectF &rect) { + storeZoomReset(); qreal logLeftX = rect.left() * (m_logRightX - m_logLeftX) / m_size.width() + m_logLeftX; qreal logRightX = rect.right() * (m_logRightX - m_logLeftX) / m_size.width() + m_logLeftX; qreal leftX = qPow(m_logBaseX, logLeftX); @@ -97,6 +98,7 @@ void LogXLogYDomain::zoomIn(const QRectF &rect) void LogXLogYDomain::zoomOut(const QRectF &rect) { + storeZoomReset(); const qreal factorX = m_size.width() / rect.width(); const qreal factorY = m_size.height() / rect.height(); diff --git a/src/domain/logxlogypolardomain.cpp b/src/domain/logxlogypolardomain.cpp index a193ce1..1c3cc84 100644 --- a/src/domain/logxlogypolardomain.cpp +++ b/src/domain/logxlogypolardomain.cpp @@ -78,6 +78,7 @@ void LogXLogYPolarDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal max void LogXLogYPolarDomain::zoomIn(const QRectF &rect) { + storeZoomReset(); qreal logLeftX = rect.left() * (m_logRightX - m_logLeftX) / m_size.width() + m_logLeftX; qreal logRightX = rect.right() * (m_logRightX - m_logLeftX) / m_size.width() + m_logLeftX; qreal leftX = qPow(m_logBaseX, logLeftX); @@ -97,6 +98,7 @@ void LogXLogYPolarDomain::zoomIn(const QRectF &rect) void LogXLogYPolarDomain::zoomOut(const QRectF &rect) { + storeZoomReset(); const qreal factorX = m_size.width() / rect.width(); qreal logLeftX = m_logLeftX + (m_logRightX - m_logLeftX) / 2.0 * (1.0 - factorX); diff --git a/src/domain/logxydomain.cpp b/src/domain/logxydomain.cpp index da6e210..62a041c 100644 --- a/src/domain/logxydomain.cpp +++ b/src/domain/logxydomain.cpp @@ -70,6 +70,7 @@ void LogXYDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY) void LogXYDomain::zoomIn(const QRectF &rect) { + storeZoomReset(); qreal logLeftX = rect.left() * (m_logRightX - m_logLeftX) / m_size.width() + m_logLeftX; qreal logRightX = rect.right() * (m_logRightX - m_logLeftX) / m_size.width() + m_logLeftX; qreal leftX = qPow(m_logBaseX, logLeftX); @@ -89,6 +90,7 @@ void LogXYDomain::zoomIn(const QRectF &rect) void LogXYDomain::zoomOut(const QRectF &rect) { + storeZoomReset(); const qreal factorX = m_size.width() / rect.width(); qreal logLeftX = m_logLeftX + (m_logRightX - m_logLeftX) / 2 * (1 - factorX); diff --git a/src/domain/logxypolardomain.cpp b/src/domain/logxypolardomain.cpp index b08f6a0..b720352 100644 --- a/src/domain/logxypolardomain.cpp +++ b/src/domain/logxypolardomain.cpp @@ -70,6 +70,7 @@ void LogXYPolarDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY) void LogXYPolarDomain::zoomIn(const QRectF &rect) { + storeZoomReset(); qreal logLeftX = rect.left() * (m_logRightX - m_logLeftX) / m_size.width() + m_logLeftX; qreal logRightX = rect.right() * (m_logRightX - m_logLeftX) / m_size.width() + m_logLeftX; qreal leftX = qPow(m_logBaseX, logLeftX); @@ -89,6 +90,7 @@ void LogXYPolarDomain::zoomIn(const QRectF &rect) void LogXYPolarDomain::zoomOut(const QRectF &rect) { + storeZoomReset(); const qreal factorX = m_size.width() / rect.width(); qreal logLeftX = m_logLeftX + (m_logRightX - m_logLeftX) / 2.0 * (1.0 - factorX); diff --git a/src/domain/xlogydomain.cpp b/src/domain/xlogydomain.cpp index 850eb99..9934cbd 100644 --- a/src/domain/xlogydomain.cpp +++ b/src/domain/xlogydomain.cpp @@ -70,6 +70,7 @@ void XLogYDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY) void XLogYDomain::zoomIn(const QRectF &rect) { + storeZoomReset(); qreal dx = spanX() / m_size.width(); qreal maxX = m_maxX; qreal minX = m_minX; @@ -89,6 +90,7 @@ void XLogYDomain::zoomIn(const QRectF &rect) void XLogYDomain::zoomOut(const QRectF &rect) { + storeZoomReset(); qreal dx = spanX() / rect.width(); qreal maxX = m_maxX; qreal minX = m_minX; diff --git a/src/domain/xlogypolardomain.cpp b/src/domain/xlogypolardomain.cpp index 730a9dc..1843191 100644 --- a/src/domain/xlogypolardomain.cpp +++ b/src/domain/xlogypolardomain.cpp @@ -70,6 +70,7 @@ void XLogYPolarDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY) void XLogYPolarDomain::zoomIn(const QRectF &rect) { + storeZoomReset(); qreal dx = spanX() / m_size.width(); qreal maxX = m_maxX; qreal minX = m_minX; @@ -89,6 +90,7 @@ void XLogYPolarDomain::zoomIn(const QRectF &rect) void XLogYPolarDomain::zoomOut(const QRectF &rect) { + storeZoomReset(); qreal dx = spanX() / rect.width(); qreal maxX = m_maxX; qreal minX = m_minX; diff --git a/src/domain/xydomain.cpp b/src/domain/xydomain.cpp index 8ac1f0a..f2f37b3 100644 --- a/src/domain/xydomain.cpp +++ b/src/domain/xydomain.cpp @@ -61,6 +61,7 @@ void XYDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY) void XYDomain::zoomIn(const QRectF &rect) { + storeZoomReset(); qreal dx = spanX() / m_size.width(); qreal dy = spanY() / m_size.height(); @@ -79,6 +80,7 @@ void XYDomain::zoomIn(const QRectF &rect) void XYDomain::zoomOut(const QRectF &rect) { + storeZoomReset(); qreal dx = spanX() / rect.width(); qreal dy = spanY() / rect.height(); diff --git a/src/domain/xypolardomain.cpp b/src/domain/xypolardomain.cpp index e947129..1e8c260 100644 --- a/src/domain/xypolardomain.cpp +++ b/src/domain/xypolardomain.cpp @@ -61,6 +61,7 @@ void XYPolarDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY) void XYPolarDomain::zoomIn(const QRectF &rect) { + storeZoomReset(); qreal dx = spanX() / m_size.width(); qreal dy = spanY() / m_size.height(); @@ -79,6 +80,7 @@ void XYPolarDomain::zoomIn(const QRectF &rect) void XYPolarDomain::zoomOut(const QRectF &rect) { + storeZoomReset(); qreal dx = spanX() / rect.width(); qreal dy = spanY() / rect.height(); diff --git a/src/qchart.cpp b/src/qchart.cpp index 93e2815..6eed3a5 100644 --- a/src/qchart.cpp +++ b/src/qchart.cpp @@ -347,6 +347,26 @@ void QChart::zoom(qreal factor) d_ptr->zoomOut(1.0 / factor); } + +/*! + Resets the series domains to what they were before any zoom method was called. + Note that this will also reset any scrolls and explicit axis range settings done between + the first zoom operation and calling this method. If no zoom operation has been + done, this method does nothing. + */ +void QChart::zoomReset() +{ + d_ptr->zoomReset(); +} + +/*! + Returns true if any series has a zoomed domain. + */ +bool QChart::isZoomed() +{ + return d_ptr->isZoomed(); +} + /*! Returns a pointer to the horizontal axis attached to the specified \a series. If no \a series is specified, the first horizontal axis added to the chart is returned. @@ -749,6 +769,16 @@ void QChartPrivate::zoomIn(const QRectF &rect) } +void QChartPrivate::zoomReset() +{ + m_dataset->zoomResetDomain(); +} + +bool QChartPrivate::isZoomed() +{ + return m_dataset->isZoomedDomain(); +} + void QChartPrivate::zoomOut(qreal factor) { const QRectF geometry = m_presenter->geometry(); diff --git a/src/qchart.h b/src/qchart.h index 6f47830..1c6e8c9 100644 --- a/src/qchart.h +++ b/src/qchart.h @@ -126,6 +126,8 @@ public: void zoomIn(const QRectF &rect); void zoom(qreal factor); + void zoomReset(); + bool isZoomed(); void scroll(qreal dx, qreal dy); diff --git a/src/qchart_p.h b/src/qchart_p.h index e8a4be3..4794e03 100644 --- a/src/qchart_p.h +++ b/src/qchart_p.h @@ -61,6 +61,8 @@ public: void zoomIn(qreal factor); void zoomOut(qreal factor); void zoomIn(const QRectF &rect); + void zoomReset(); + bool isZoomed(); void scroll(qreal dx, qreal dy); }; diff --git a/src/qchartview.cpp b/src/qchartview.cpp index 6296109..7695fd7 100644 --- a/src/qchartview.cpp +++ b/src/qchartview.cpp @@ -177,7 +177,7 @@ void QChartView::mouseMoveEvent(QMouseEvent *event) /*! If left mouse button is released and the rubber band is enabled then \a event is accepted and the view is zoomed into the rect specified by the rubber band. - If it is a right mouse button \a event then the rubber band is dismissed and the zoom is canceled. + If it is a right mouse button \a event then the view is zoomed out. */ void QChartView::mouseReleaseEvent(QMouseEvent *event) { diff --git a/tests/auto/qchart/tst_qchart.cpp b/tests/auto/qchart/tst_qchart.cpp index 71f7d0d..cbc81b4 100644 --- a/tests/auto/qchart/tst_qchart.cpp +++ b/tests/auto/qchart/tst_qchart.cpp @@ -105,6 +105,7 @@ private slots: void zoomIn(); void zoomOut_data(); void zoomOut(); + void zoomReset(); void createDefaultAxesForLineSeries_data(); void createDefaultAxesForLineSeries(); void axisPolarOrientation(); @@ -852,6 +853,77 @@ void tst_QChart::zoomOut() } +void tst_QChart::zoomReset() +{ + createTestData(); + m_chart->createDefaultAxes(); + QValueAxis *axisX = qobject_cast(m_chart->axisX()); + QVERIFY(axisX != 0); + QValueAxis *axisY = qobject_cast(m_chart->axisY()); + QVERIFY(axisY != 0); + + qreal minX = axisX->min(); + qreal minY = axisY->min(); + qreal maxX = axisX->max(); + qreal maxY = axisY->max(); + + QVERIFY(!m_chart->isZoomed()); + + m_chart->zoomIn(); + + QVERIFY(m_chart->isZoomed()); + QVERIFY(minX < axisX->min()); + QVERIFY(maxX > axisX->max()); + QVERIFY(minY < axisY->min()); + QVERIFY(maxY > axisY->max()); + + m_chart->zoomReset(); + + // Reset after zoomIn should restore originals + QVERIFY(!m_chart->isZoomed()); + QVERIFY(minX == axisX->min()); + QVERIFY(maxX == axisX->max()); + QVERIFY(minY == axisY->min()); + QVERIFY(maxY == axisY->max()); + + m_chart->zoomOut(); + + QVERIFY(m_chart->isZoomed()); + QVERIFY(minX > axisX->min()); + QVERIFY(maxX < axisX->max()); + QVERIFY(minY > axisY->min()); + QVERIFY(maxY < axisY->max()); + + m_chart->zoomReset(); + + // Reset after zoomOut should restore originals + QVERIFY(!m_chart->isZoomed()); + QVERIFY(minX == axisX->min()); + QVERIFY(maxX == axisX->max()); + QVERIFY(minY == axisY->min()); + QVERIFY(maxY == axisY->max()); + + axisX->setRange(234, 345); + axisY->setRange(345, 456); + + minX = axisX->min(); + minY = axisY->min(); + maxX = axisX->max(); + maxY = axisY->max(); + + QVERIFY(!m_chart->isZoomed()); + + m_chart->zoomReset(); + + // Reset without zoom should not change anything + QVERIFY(!m_chart->isZoomed()); + QVERIFY(minX == axisX->min()); + QVERIFY(maxX == axisX->max()); + QVERIFY(minY == axisY->min()); + QVERIFY(maxY == axisY->max()); + +} + void tst_QChart::createDefaultAxesForLineSeries_data() { QTest::addColumn("series1minX");