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() )
00356         return;
00357 
00358     if ( d_data->maxStackDepth >= 0 &&
00359         int(zoomStack.count()) > d_data->maxStackDepth )
00360     {
00361         return;
00362     }
00363 
00364     if ( zoomRectIndex < 0 || zoomRectIndex > int(zoomStack.count()) )
00365         zoomRectIndex = zoomStack.count() - 1;
00366 
00367     const bool doRescale = zoomStack[zoomRectIndex] != zoomRect();
00368 
00369     d_data->zoomStack = zoomStack;
00370     d_data->zoomRectIndex = uint(zoomRectIndex);
00371 
00372     if ( doRescale )
00373     {
00374         rescale();
00375         emit zoomed(zoomRect());
00376     }
00377 }
00378 
00385 void QwtPlotZoomer::rescale()
00386 {
00387     QwtPlot *plt = plot();
00388     if ( !plt )
00389         return;
00390 
00391     const QwtDoubleRect &rect = d_data->zoomStack[d_data->zoomRectIndex];
00392     if ( rect != scaleRect() )
00393     {
00394         const bool doReplot = plt->autoReplot();
00395         plt->setAutoReplot(false);
00396 
00397         double x1 = rect.left();
00398         double x2 = rect.right();
00399         if ( plt->axisScaleDiv(xAxis())->lBound() > 
00400             plt->axisScaleDiv(xAxis())->hBound() )
00401         {
00402             qSwap(x1, x2);
00403         }
00404 
00405         plt->setAxisScale(xAxis(), x1, x2);
00406 
00407         double y1 = rect.top();
00408         double y2 = rect.bottom();
00409         if ( plt->axisScaleDiv(yAxis())->lBound() > 
00410             plt->axisScaleDiv(yAxis())->hBound() )
00411         {
00412             qSwap(y1, y2);
00413         }
00414         plt->setAxisScale(yAxis(), y1, y2);
00415 
00416         plt->setAutoReplot(doReplot);
00417 
00418         plt->replot();
00419     }
00420 }
00421 
00429 void QwtPlotZoomer::setAxis(int xAxis, int yAxis)
00430 {
00431     if ( xAxis != QwtPlotPicker::xAxis() || yAxis != QwtPlotPicker::yAxis() )
00432     {
00433         QwtPlotPicker::setAxis(xAxis, yAxis);
00434         setZoomBase(scaleRect());
00435     }
00436 }
00437 
00448 void QwtPlotZoomer::widgetMouseReleaseEvent(QMouseEvent *me)
00449 {
00450     if ( mouseMatch(MouseSelect2, me) )
00451         zoom(0);
00452     else if ( mouseMatch(MouseSelect3, me) )
00453         zoom(-1);
00454     else if ( mouseMatch(MouseSelect6, me) )
00455         zoom(+1);
00456     else 
00457         QwtPlotPicker::widgetMouseReleaseEvent(me);
00458 }
00459 
00471 void QwtPlotZoomer::widgetKeyPressEvent(QKeyEvent *ke)
00472 {
00473     if ( !isActive() )
00474     {
00475         if ( keyMatch(KeyUndo, ke) )
00476             zoom(-1);
00477         else if ( keyMatch(KeyRedo, ke) )
00478             zoom(+1);
00479         else if ( keyMatch(KeyHome, ke) )
00480             zoom(0);
00481     }
00482 
00483     QwtPlotPicker::widgetKeyPressEvent(ke);
00484 }
00485 
00494 void QwtPlotZoomer::moveBy(double dx, double dy)
00495 {
00496     const QwtDoubleRect &rect = d_data->zoomStack[d_data->zoomRectIndex];
00497     move(rect.left() + dx, rect.top() + dy);
00498 }
00499 
00509 void QwtPlotZoomer::move(double x, double y)
00510 {
00511     if ( x < zoomBase().left() )
00512         x = zoomBase().left();
00513     if ( x > zoomBase().right() - zoomRect().width() )
00514         x = zoomBase().right() - zoomRect().width();
00515 
00516     if ( y < zoomBase().top() )
00517         y = zoomBase().top();
00518     if ( y > zoomBase().bottom() - zoomRect().height() )
00519         y = zoomBase().bottom() - zoomRect().height();
00520 
00521     if ( x != zoomRect().left() || y != zoomRect().top() )
00522     {
00523         d_data->zoomStack[d_data->zoomRectIndex].moveTo(x, y);
00524         rescale();
00525     }
00526 }
00527 
00539 bool QwtPlotZoomer::accept(QwtPolygon &pa) const
00540 {
00541     if ( pa.count() < 2 )
00542         return false;
00543 
00544     QRect rect = QRect(pa[0], pa[int(pa.count()) - 1]);
00545 #if QT_VERSION < 0x040000
00546     rect = rect.normalize();
00547 #else
00548     rect = rect.normalized();
00549 #endif
00550 
00551     const int minSize = 2;
00552     if (rect.width() < minSize && rect.height() < minSize )
00553         return false; 
00554 
00555     const int minZoomSize = 11;
00556 
00557     const QPoint center = rect.center();
00558     rect.setSize(rect.size().expandedTo(QSize(minZoomSize, minZoomSize)));
00559     rect.moveCenter(center);
00560 
00561     pa.resize(2);
00562     pa[0] = rect.topLeft();
00563     pa[1] = rect.bottomRight();
00564 
00565     return true;
00566 }
00567 
00573 QwtDoubleSize QwtPlotZoomer::minZoomSize() const
00574 {
00575     return QwtDoubleSize(
00576         d_data->zoomStack[0].width() / 10e4,
00577         d_data->zoomStack[0].height() / 10e4
00578     );
00579 }
00580 
00587 void QwtPlotZoomer::begin()
00588 {
00589     if ( d_data->maxStackDepth >= 0 )
00590     {
00591         if ( d_data->zoomRectIndex >= uint(d_data->maxStackDepth) )
00592             return;
00593     }
00594 
00595     const QwtDoubleSize minSize = minZoomSize();
00596     if ( minSize.isValid() )
00597     {
00598         const QwtDoubleSize sz = 
00599             d_data->zoomStack[d_data->zoomRectIndex].size() * 0.9999;
00600 
00601         if ( minSize.width() >= sz.width() &&
00602             minSize.height() >= sz.height() )
00603         {
00604             return;
00605         }
00606     }
00607 
00608     QwtPlotPicker::begin();
00609 }
00610 
00617 bool QwtPlotZoomer::end(bool ok)
00618 {
00619     ok = QwtPlotPicker::end(ok);
00620     if (!ok)
00621         return false;
00622 
00623     QwtPlot *plot = QwtPlotZoomer::plot();
00624     if ( !plot )
00625         return false;
00626 
00627     const QwtPolygon &pa = selection();
00628     if ( pa.count() < 2 )
00629         return false;
00630 
00631     QRect rect = QRect(pa[0], pa[int(pa.count() - 1)]);
00632 #if QT_VERSION < 0x040000
00633     rect = rect.normalize();
00634 #else
00635     rect = rect.normalized();
00636 #endif
00637 
00638 
00639     QwtDoubleRect zoomRect = invTransform(rect).normalized();
00640 
00641     const QwtDoublePoint center = zoomRect.center();
00642     zoomRect.setSize(zoomRect.size().expandedTo(minZoomSize()));
00643     zoomRect.moveCenter(center);
00644 
00645     zoom(zoomRect);
00646 
00647     return true;
00648 }
00649 
00661 void QwtPlotZoomer::setSelectionFlags(int flags)
00662 {
00663     // we accept only rects
00664     flags &= ~(PointSelection | PolygonSelection);
00665     flags |= RectSelection;
00666 
00667     QwtPlotPicker::setSelectionFlags(flags);
00668 }

Generated on Sun Mar 22 16:54:08 2009 for Qwt User's Guide by  doxygen 1.5.0