qwt_plot_zoomer.cpp

00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
00002  * Qwt Widget Library
00003  * Copyright (C) 1997   Josef Wilgen
00004  * Copyright (C) 2002   Uwe Rathmann
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the Qwt License, Version 1.0
00008  *****************************************************************************/
00009 
00010 // vim: expandtab
00011 
00012 #include <math.h>
00013 #include "qwt_plot.h"
00014 #include "qwt_plot_canvas.h"
00015 #include "qwt_plot_zoomer.h"
00016 #include "qwt_scale_div.h"
00017 #if QT_VERSION < 0x040000
00018 typedef QValueStack<QwtDoubleRect> QwtZoomStack;
00019 #else
00020 typedef QStack<QwtDoubleRect> QwtZoomStack;
00021 #endif
00022 
00023 class QwtPlotZoomer::PrivateData
00024 {
00025 public:
00026     uint zoomRectIndex;
00027     QwtZoomStack zoomStack;
00028 
00029     int maxStackDepth;
00030 };
00031 
00051 QwtPlotZoomer::QwtPlotZoomer(QwtPlotCanvas *canvas, bool doReplot):
00052     QwtPlotPicker(canvas)
00053 {
00054     if ( canvas )
00055         init(RectSelection & ClickSelection, ActiveOnly, doReplot);
00056 }
00057 
00075 QwtPlotZoomer::QwtPlotZoomer(int xAxis, int yAxis,
00076         QwtPlotCanvas *canvas, bool doReplot):
00077     QwtPlotPicker(xAxis, yAxis, canvas)
00078 {
00079     if ( canvas )
00080         init(RectSelection & ClickSelection, ActiveOnly, doReplot);
00081 }
00082 
00103 QwtPlotZoomer::QwtPlotZoomer(int xAxis, int yAxis, int selectionFlags,
00104         DisplayMode trackerMode, QwtPlotCanvas *canvas, bool doReplot):
00105     QwtPlotPicker(xAxis, yAxis, canvas)
00106 {
00107     if ( canvas )
00108         init(selectionFlags, trackerMode, doReplot);
00109 }
00110 
00112 void QwtPlotZoomer::init(int selectionFlags, 
00113     DisplayMode trackerMode, bool doReplot)
00114 {
00115     d_data = new PrivateData;
00116 
00117     d_data->maxStackDepth = -1;
00118 
00119     setSelectionFlags(selectionFlags);
00120     setTrackerMode(trackerMode);
00121     setRubberBand(RectRubberBand);
00122 
00123     if ( doReplot && plot() )
00124         plot()->replot();
00125 
00126     setZoomBase(scaleRect());
00127 }
00128 
00129 QwtPlotZoomer::~QwtPlotZoomer()
00130 {
00131     delete d_data;
00132 }
00133 
00145 void QwtPlotZoomer::setMaxStackDepth(int depth)
00146 {
00147     d_data->maxStackDepth = depth;
00148 
00149     if ( depth >= 0 )
00150     {
00151         // unzoom if the current depth is below d_data->maxStackDepth
00152 
00153         const int zoomOut = 
00154             int(d_data->zoomStack.count()) - 1 - depth; // -1 for the zoom base
00155 
00156         if ( zoomOut > 0 )
00157         {
00158             zoom(-zoomOut);
00159             for ( int i = int(d_data->zoomStack.count()) - 1; 
00160                 i > int(d_data->zoomRectIndex); i-- )
00161             {
00162                 (void)d_data->zoomStack.pop(); // remove trailing rects
00163             }
00164         }
00165     }
00166 }
00167 
00172 int QwtPlotZoomer::maxStackDepth() const
00173 {
00174     return d_data->maxStackDepth;
00175 }
00176 
00183 const QwtZoomStack &QwtPlotZoomer::zoomStack() const
00184 {
00185     return d_data->zoomStack;
00186 }
00187 
00192 QwtDoubleRect QwtPlotZoomer::zoomBase() const
00193 {
00194     return d_data->zoomStack[0];
00195 }
00196 
00206 void QwtPlotZoomer::setZoomBase(bool doReplot)
00207 {
00208     QwtPlot *plt = plot();
00209     if ( plt == NULL )
00210         return;
00211 
00212     if ( doReplot )
00213         plt->replot();
00214 
00215     d_data->zoomStack.clear();
00216     d_data->zoomStack.push(scaleRect());
00217     d_data->zoomRectIndex = 0;
00218 
00219     rescale();
00220 }
00221 
00232 void QwtPlotZoomer::setZoomBase(const QwtDoubleRect &base)
00233 {
00234     const QwtPlot *plt = plot();
00235     if ( !plt )
00236         return;
00237 
00238     const QwtDoubleRect sRect = scaleRect();
00239     const QwtDoubleRect bRect = base | sRect;
00240 
00241     d_data->zoomStack.clear();
00242     d_data->zoomStack.push(bRect);
00243     d_data->zoomRectIndex = 0;
00244 
00245     if ( base != sRect )
00246     {
00247         d_data->zoomStack.push(sRect);
00248         d_data->zoomRectIndex++;
00249     }
00250 
00251     rescale();
00252 }
00253 
00259 QwtDoubleRect QwtPlotZoomer::zoomRect() const
00260 {
00261     return d_data->zoomStack[d_data->zoomRectIndex];
00262 }
00263 
00267 uint QwtPlotZoomer::zoomRectIndex() const
00268 {
00269     return d_data->zoomRectIndex;
00270 }
00271 
00283 void QwtPlotZoomer::zoom(const QwtDoubleRect &rect)
00284 {   
00285     if ( d_data->maxStackDepth >= 0 && 
00286         int(d_data->zoomRectIndex) >= d_data->maxStackDepth )
00287     {
00288         return;
00289     }
00290 
00291     const QwtDoubleRect zoomRect = d_data->zoomStack[0] & rect.normalized();
00292     if ( zoomRect != d_data->zoomStack[d_data->zoomRectIndex] )
00293     {
00294         for ( uint i = int(d_data->zoomStack.count()) - 1; 
00295            i > d_data->zoomRectIndex; i-- )
00296         {
00297             (void)d_data->zoomStack.pop();
00298         }
00299 
00300         d_data->zoomStack.push(zoomRect);
00301         d_data->zoomRectIndex++;
00302 
00303         rescale();
00304 
00305         emit zoomed(zoomRect);
00306     }
00307 }
00308 
00320 void QwtPlotZoomer::zoom(int offset)
00321 {
00322     if ( offset == 0 )
00323         d_data->zoomRectIndex = 0;
00324     else
00325     {
00326         int newIndex = d_data->zoomRectIndex + offset;
00327         newIndex = qwtMax(0, newIndex);
00328         newIndex = qwtMin(int(d_data->zoomStack.count()) - 1, newIndex);
00329 
00330         d_data->zoomRectIndex = uint(newIndex);
00331     }
00332 
00333     rescale();
00334 
00335     emit zoomed(zoomRect());
00336 }
00337 
00352 void QwtPlotZoomer::setZoomStack(
00353     const QwtZoomStack &zoomStack, int zoomRectIndex)
00354 {
00355     if ( zoomStack.isEmpty() || int(zoomStack.count()) > d_data->maxStackDepth )
00356         return;
00357 
00358     if ( zoomRectIndex < 0 || zoomRectIndex > int(zoomStack.count()) )
00359         zoomRectIndex = zoomStack.count() - 1;
00360 
00361     const bool doRescale = zoomStack[zoomRectIndex] != zoomRect();
00362 
00363     d_data->zoomStack = zoomStack;
00364     d_data->zoomRectIndex = uint(zoomRectIndex);
00365 
00366     if ( doRescale )
00367     {
00368         rescale();
00369         emit zoomed(zoomRect());
00370     }
00371 }
00372 
00379 void QwtPlotZoomer::rescale()
00380 {
00381     QwtPlot *plt = plot();
00382     if ( !plt )
00383         return;
00384 
00385     const QwtDoubleRect &rect = d_data->zoomStack[d_data->zoomRectIndex];
00386     if ( rect != scaleRect() )
00387     {
00388         const bool doReplot = plt->autoReplot();
00389         plt->setAutoReplot(false);
00390 
00391         double x1 = rect.left();
00392         double x2 = rect.right();
00393         if ( plt->axisScaleDiv(xAxis())->lBound() > 
00394             plt->axisScaleDiv(xAxis())->hBound() )
00395         {
00396             qSwap(x1, x2);
00397         }
00398 
00399         plt->setAxisScale(xAxis(), x1, x2);
00400 
00401         double y1 = rect.top();
00402         double y2 = rect.bottom();
00403         if ( plt->axisScaleDiv(yAxis())->lBound() > 
00404             plt->axisScaleDiv(yAxis())->hBound() )
00405         {
00406             qSwap(y1, y2);
00407         }
00408         plt->setAxisScale(yAxis(), y1, y2);
00409 
00410         plt->setAutoReplot(doReplot);
00411 
00412         plt->replot();
00413     }
00414 }
00415 
00423 void QwtPlotZoomer::setAxis(int xAxis, int yAxis)
00424 {
00425     if ( xAxis != QwtPlotPicker::xAxis() || yAxis != QwtPlotPicker::yAxis() )
00426     {
00427         QwtPlotPicker::setAxis(xAxis, yAxis);
00428         setZoomBase(scaleRect());
00429     }
00430 }
00431 
00442 void QwtPlotZoomer::widgetMouseReleaseEvent(QMouseEvent *me)
00443 {
00444     if ( mouseMatch(MouseSelect2, me) )
00445         zoom(0);
00446     else if ( mouseMatch(MouseSelect3, me) )
00447         zoom(-1);
00448     else if ( mouseMatch(MouseSelect6, me) )
00449         zoom(+1);
00450     else 
00451         QwtPlotPicker::widgetMouseReleaseEvent(me);
00452 }
00453 
00465 void QwtPlotZoomer::widgetKeyPressEvent(QKeyEvent *ke)
00466 {
00467     if ( !isActive() )
00468     {
00469         if ( keyMatch(KeyUndo, ke) )
00470             zoom(-1);
00471         else if ( keyMatch(KeyRedo, ke) )
00472             zoom(+1);
00473         else if ( keyMatch(KeyHome, ke) )
00474             zoom(0);
00475     }
00476 
00477     QwtPlotPicker::widgetKeyPressEvent(ke);
00478 }
00479 
00488 void QwtPlotZoomer::moveBy(double dx, double dy)
00489 {
00490     const QwtDoubleRect &rect = d_data->zoomStack[d_data->zoomRectIndex];
00491     move(rect.left() + dx, rect.top() + dy);
00492 }
00493 
00503 void QwtPlotZoomer::move(double x, double y)
00504 {
00505     if ( x < zoomBase().left() )
00506         x = zoomBase().left();
00507     if ( x > zoomBase().right() - zoomRect().width() )
00508         x = zoomBase().right() - zoomRect().width();
00509 
00510     if ( y < zoomBase().top() )
00511         y = zoomBase().top();
00512     if ( y > zoomBase().bottom() - zoomRect().height() )
00513         y = zoomBase().bottom() - zoomRect().height();
00514 
00515     if ( x != zoomRect().left() || y != zoomRect().top() )
00516     {
00517         d_data->zoomStack[d_data->zoomRectIndex].moveTo(x, y);
00518         rescale();
00519     }
00520 }
00521 
00533 bool QwtPlotZoomer::accept(QwtPolygon &pa) const
00534 {
00535     if ( pa.count() < 2 )
00536         return false;
00537 
00538     QRect rect = QRect(pa[0], pa[int(pa.count()) - 1]);
00539 #if QT_VERSION < 0x040000
00540     rect = rect.normalize();
00541 #else
00542     rect = rect.normalized();
00543 #endif
00544 
00545     const int minSize = 2;
00546     if (rect.width() < minSize && rect.height() < minSize )
00547         return false; 
00548 
00549     const int minZoomSize = 11;
00550 
00551     const QPoint center = rect.center();
00552     rect.setSize(rect.size().expandedTo(QSize(minZoomSize, minZoomSize)));
00553     rect.moveCenter(center);
00554 
00555     pa.resize(2);
00556     pa[0] = rect.topLeft();
00557     pa[1] = rect.bottomRight();
00558 
00559     return true;
00560 }
00561 
00567 QwtDoubleSize QwtPlotZoomer::minZoomSize() const
00568 {
00569     return QwtDoubleSize(
00570         d_data->zoomStack[0].width() / 10e4,
00571         d_data->zoomStack[0].height() / 10e4
00572     );
00573 }
00574 
00581 void QwtPlotZoomer::begin()
00582 {
00583     if ( d_data->maxStackDepth >= 0 )
00584     {
00585         if ( d_data->zoomRectIndex >= uint(d_data->maxStackDepth) )
00586             return;
00587     }
00588 
00589     const QwtDoubleSize minSize = minZoomSize();
00590     if ( minSize.isValid() )
00591     {
00592         const QwtDoubleSize sz = 
00593             d_data->zoomStack[d_data->zoomRectIndex].size() * 0.9999;
00594 
00595         if ( minSize.width() >= sz.width() &&
00596             minSize.height() >= sz.height() )
00597         {
00598             return;
00599         }
00600     }
00601 
00602     QwtPlotPicker::begin();
00603 }
00604 
00611 bool QwtPlotZoomer::end(bool ok)
00612 {
00613     ok = QwtPlotPicker::end(ok);
00614     if (!ok)
00615         return false;
00616 
00617     QwtPlot *plot = QwtPlotZoomer::plot();
00618     if ( !plot )
00619         return false;
00620 
00621     const QwtPolygon &pa = selection();
00622     if ( pa.count() < 2 )
00623         return false;
00624 
00625     QRect rect = QRect(pa[0], pa[int(pa.count() - 1)]);
00626 #if QT_VERSION < 0x040000
00627     rect = rect.normalize();
00628 #else
00629     rect = rect.normalized();
00630 #endif
00631 
00632 
00633     QwtDoubleRect zoomRect = invTransform(rect).normalized();
00634 
00635     const QwtDoublePoint center = zoomRect.center();
00636     zoomRect.setSize(zoomRect.size().expandedTo(minZoomSize()));
00637     zoomRect.moveCenter(center);
00638 
00639     zoom(zoomRect);
00640 
00641     return true;
00642 }
00643 
00655 void QwtPlotZoomer::setSelectionFlags(int flags)
00656 {
00657     // we accept only rects
00658     flags &= ~(PointSelection | PolygonSelection);
00659     flags |= RectSelection;
00660 
00661     QwtPlotPicker::setSelectionFlags(flags);
00662 }

Generated on Sat May 24 18:47:40 2008 for Qwt User's Guide by  doxygen 1.5.0