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 
00181 const QwtZoomStack &QwtPlotZoomer::zoomStack() const
00182 {
00183     return d_data->zoomStack;
00184 }
00185 
00190 QwtDoubleRect QwtPlotZoomer::zoomBase() const
00191 {
00192     return d_data->zoomStack[0];
00193 }
00194 
00208 void QwtPlotZoomer::setZoomBase()
00209 {
00210     const QwtPlot *plt = plot();
00211     if ( !plt )
00212         return;
00213 
00214     d_data->zoomStack.clear();
00215     d_data->zoomStack.push(scaleRect());
00216     d_data->zoomRectIndex = 0;
00217 
00218     rescale();
00219 }
00220 
00231 void QwtPlotZoomer::setZoomBase(const QwtDoubleRect &base)
00232 {
00233     const QwtPlot *plt = plot();
00234     if ( !plt )
00235         return;
00236 
00237     const QwtDoubleRect sRect = scaleRect();
00238     const QwtDoubleRect bRect = base | sRect;
00239 
00240     d_data->zoomStack.clear();
00241     d_data->zoomStack.push(bRect);
00242     d_data->zoomRectIndex = 0;
00243 
00244     if ( base != sRect )
00245     {
00246         d_data->zoomStack.push(sRect);
00247         d_data->zoomRectIndex++;
00248     }
00249 
00250     rescale();
00251 }
00252 
00258 QwtDoubleRect QwtPlotZoomer::zoomRect() const
00259 {
00260     return d_data->zoomStack[d_data->zoomRectIndex];
00261 }
00262 
00266 uint QwtPlotZoomer::zoomRectIndex() const
00267 {
00268     return d_data->zoomRectIndex;
00269 }
00270 
00282 void QwtPlotZoomer::zoom(const QwtDoubleRect &rect)
00283 {   
00284     if ( d_data->maxStackDepth >= 0 && 
00285         int(d_data->zoomRectIndex) >= d_data->maxStackDepth )
00286     {
00287         return;
00288     }
00289 
00290     const QwtDoubleRect zoomRect = d_data->zoomStack[0] & rect.normalized();
00291     if ( zoomRect != d_data->zoomStack[d_data->zoomRectIndex] )
00292     {
00293         for ( uint i = int(d_data->zoomStack.count()) - 1; 
00294            i > d_data->zoomRectIndex; i-- )
00295         {
00296             (void)d_data->zoomStack.pop();
00297         }
00298 
00299         d_data->zoomStack.push(zoomRect);
00300         d_data->zoomRectIndex++;
00301 
00302         rescale();
00303 
00304         emit zoomed(zoomRect);
00305     }
00306 }
00307 
00319 void QwtPlotZoomer::zoom(int offset)
00320 {
00321     if ( offset == 0 )
00322         d_data->zoomRectIndex = 0;
00323     else
00324     {
00325         int newIndex = d_data->zoomRectIndex + offset;
00326         newIndex = qwtMax(0, newIndex);
00327         newIndex = qwtMin(int(d_data->zoomStack.count()) - 1, newIndex);
00328 
00329         d_data->zoomRectIndex = uint(newIndex);
00330     }
00331 
00332     rescale();
00333 
00334     emit zoomed(zoomRect());
00335 }
00336 
00343 void QwtPlotZoomer::rescale()
00344 {
00345     QwtPlot *plt = plot();
00346     if ( !plt )
00347         return;
00348 
00349     const QwtDoubleRect &rect = d_data->zoomStack[d_data->zoomRectIndex];
00350     if ( rect != scaleRect() )
00351     {
00352         const bool doReplot = plt->autoReplot();
00353         plt->setAutoReplot(false);
00354 
00355         double x1 = rect.left();
00356         double x2 = rect.right();
00357         if ( plt->axisScaleDiv(xAxis())->lBound() > 
00358             plt->axisScaleDiv(xAxis())->hBound() )
00359         {
00360             qSwap(x1, x2);
00361         }
00362 
00363         plt->setAxisScale(xAxis(), x1, x2);
00364 
00365         double y1 = rect.top();
00366         double y2 = rect.bottom();
00367         if ( plt->axisScaleDiv(yAxis())->lBound() > 
00368             plt->axisScaleDiv(yAxis())->hBound() )
00369         {
00370             qSwap(y1, y2);
00371         }
00372         plt->setAxisScale(yAxis(), y1, y2);
00373 
00374         plt->setAutoReplot(doReplot);
00375 
00376         plt->replot();
00377     }
00378 }
00379 
00387 void QwtPlotZoomer::setAxis(int xAxis, int yAxis)
00388 {
00389     if ( xAxis != QwtPlotPicker::xAxis() || yAxis != QwtPlotPicker::yAxis() )
00390     {
00391         QwtPlotPicker::setAxis(xAxis, yAxis);
00392         setZoomBase(scaleRect());
00393     }
00394 }
00395 
00406 void QwtPlotZoomer::widgetMouseReleaseEvent(QMouseEvent *me)
00407 {
00408     if ( mouseMatch(MouseSelect2, me) )
00409         zoom(0);
00410     else if ( mouseMatch(MouseSelect3, me) )
00411         zoom(-1);
00412     else if ( mouseMatch(MouseSelect6, me) )
00413         zoom(+1);
00414     else 
00415         QwtPlotPicker::widgetMouseReleaseEvent(me);
00416 }
00417 
00429 void QwtPlotZoomer::widgetKeyPressEvent(QKeyEvent *ke)
00430 {
00431     if ( !isActive() )
00432     {
00433         if ( keyMatch(KeyUndo, ke) )
00434             zoom(-1);
00435         else if ( keyMatch(KeyRedo, ke) )
00436             zoom(+1);
00437         else if ( keyMatch(KeyHome, ke) )
00438             zoom(0);
00439     }
00440 
00441     QwtPlotPicker::widgetKeyPressEvent(ke);
00442 }
00443 
00452 void QwtPlotZoomer::moveBy(double dx, double dy)
00453 {
00454     const QwtDoubleRect &rect = d_data->zoomStack[d_data->zoomRectIndex];
00455     move(rect.left() + dx, rect.top() + dy);
00456 }
00457 
00467 void QwtPlotZoomer::move(double x, double y)
00468 {
00469     if ( x < zoomBase().left() )
00470         x = zoomBase().left();
00471     if ( x > zoomBase().right() - zoomRect().width() )
00472         x = zoomBase().right() - zoomRect().width();
00473 
00474     if ( y < zoomBase().top() )
00475         y = zoomBase().top();
00476     if ( y > zoomBase().bottom() - zoomRect().height() )
00477         y = zoomBase().bottom() - zoomRect().height();
00478 
00479     if ( x != zoomRect().left() || y != zoomRect().top() )
00480     {
00481         d_data->zoomStack[d_data->zoomRectIndex].moveTo(x, y);
00482         rescale();
00483     }
00484 }
00485 
00497 bool QwtPlotZoomer::accept(QwtPolygon &pa) const
00498 {
00499     if ( pa.count() < 2 )
00500         return false;
00501 
00502     QRect rect = QRect(pa[0], pa[int(pa.count()) - 1]);
00503 #if QT_VERSION < 0x040000
00504     rect = rect.normalize();
00505 #else
00506     rect = rect.normalized();
00507 #endif
00508 
00509     const int minSize = 2;
00510     if (rect.width() < minSize && rect.height() < minSize )
00511         return false; 
00512 
00513     const int minZoomSize = 11;
00514 
00515     const QPoint center = rect.center();
00516     rect.setSize(rect.size().expandedTo(QSize(minZoomSize, minZoomSize)));
00517     rect.moveCenter(center);
00518 
00519     pa.resize(2);
00520     pa[0] = rect.topLeft();
00521     pa[1] = rect.bottomRight();
00522 
00523     return true;
00524 }
00525 
00531 QwtDoubleSize QwtPlotZoomer::minZoomSize() const
00532 {
00533     return QwtDoubleSize(
00534         d_data->zoomStack[0].width() / 10e4,
00535         d_data->zoomStack[0].height() / 10e4
00536     );
00537 }
00538 
00545 void QwtPlotZoomer::begin()
00546 {
00547     if ( d_data->maxStackDepth >= 0 )
00548     {
00549         if ( d_data->zoomRectIndex >= uint(d_data->maxStackDepth) )
00550             return;
00551     }
00552 
00553     const QwtDoubleSize minSize = minZoomSize();
00554     if ( minSize.isValid() )
00555     {
00556         const QwtDoubleSize sz = 
00557             d_data->zoomStack[d_data->zoomRectIndex].size() * 0.9999;
00558 
00559         if ( minSize.width() >= sz.width() &&
00560             minSize.height() >= sz.height() )
00561         {
00562             return;
00563         }
00564     }
00565 
00566     QwtPlotPicker::begin();
00567 }
00568 
00575 bool QwtPlotZoomer::end(bool ok)
00576 {
00577     ok = QwtPlotPicker::end(ok);
00578     if (!ok)
00579         return false;
00580 
00581     QwtPlot *plot = QwtPlotZoomer::plot();
00582     if ( !plot )
00583         return false;
00584 
00585     const QwtPolygon &pa = selection();
00586     if ( pa.count() < 2 )
00587         return false;
00588 
00589     QRect rect = QRect(pa[0], pa[int(pa.count() - 1)]);
00590 #if QT_VERSION < 0x040000
00591     rect = rect.normalize();
00592 #else
00593     rect = rect.normalized();
00594 #endif
00595 
00596 
00597     QwtDoubleRect zoomRect = invTransform(rect).normalized();
00598 
00599     const QwtDoublePoint center = zoomRect.center();
00600     zoomRect.setSize(zoomRect.size().expandedTo(minZoomSize()));
00601     zoomRect.moveCenter(center);
00602 
00603     zoom(zoomRect);
00604 
00605     return true;
00606 }
00607 
00619 void QwtPlotZoomer::setSelectionFlags(int flags)
00620 {
00621     // we accept only rects
00622     flags &= ~(PointSelection | PolygonSelection);
00623     flags |= RectSelection;
00624 
00625     QwtPlotPicker::setSelectionFlags(flags);
00626 }

Generated on Mon Feb 26 21:22:38 2007 for Qwt User's Guide by  doxygen 1.4.6