Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

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 #if QT_VERSION < 0x040000
00017 typedef QValueStack<QwtDoubleRect> QwtZoomStack;
00018 #else
00019 typedef QStack<QwtDoubleRect> QwtZoomStack;
00020 #endif
00021 
00022 
00023 class QwtPlotZoomer::PrivateData
00024 {
00025 public:
00026     uint zoomRectIndex;
00027     QwtZoomStack zoomStack;
00028 
00029     int maxStackDepth;
00030 };
00031 
00055 QwtPlotZoomer::QwtPlotZoomer(QwtPlotCanvas *canvas):
00056     QwtPlotPicker(canvas)
00057 {
00058     if ( canvas )
00059         init();
00060 }
00061 
00083 QwtPlotZoomer::QwtPlotZoomer(int xAxis, int yAxis,
00084         QwtPlotCanvas *canvas):
00085     QwtPlotPicker(xAxis, yAxis, canvas)
00086 {
00087     if ( canvas )
00088     {
00089         init();
00090     }
00091 }
00092 
00116 QwtPlotZoomer::QwtPlotZoomer(int xAxis, int yAxis, int selectionFlags,
00117         DisplayMode trackerMode, QwtPlotCanvas *canvas):
00118     QwtPlotPicker(xAxis, yAxis,canvas)
00119 {
00120     if ( canvas )
00121     {
00122         init(selectionFlags, trackerMode);
00123     }
00124 }
00125 
00127 void QwtPlotZoomer::init(int selectionFlags, DisplayMode trackerMode)
00128 {
00129     d_data = new PrivateData;
00130 
00131     d_data->maxStackDepth = -1;
00132 
00133     setSelectionFlags(selectionFlags);
00134     setTrackerMode(trackerMode);
00135     setRubberBand(RectRubberBand);
00136 
00137     setZoomBase(scaleRect());
00138 }
00139 
00140 QwtPlotZoomer::~QwtPlotZoomer()
00141 {
00142     delete d_data;
00143 }
00144 
00156 void QwtPlotZoomer::setMaxStackDepth(int depth)
00157 {
00158     d_data->maxStackDepth = depth;
00159 
00160     if ( depth >= 0 )
00161     {
00162         // unzoom if the current depth is below d_data->maxStackDepth
00163 
00164         const int zoomOut = 
00165             int(d_data->zoomStack.count()) - 1 - depth; // -1 for the zoom base
00166 
00167         if ( zoomOut > 0 )
00168         {
00169             zoom(-zoomOut);
00170             for ( int i = int(d_data->zoomStack.count()) - 1; 
00171                 i > int(d_data->zoomRectIndex); i-- )
00172             {
00173                 (void)d_data->zoomStack.pop(); // remove trailing rects
00174             }
00175         }
00176     }
00177 }
00178 
00183 int QwtPlotZoomer::maxStackDepth() const
00184 {
00185     return d_data->maxStackDepth;
00186 }
00187 
00192 const QwtZoomStack &QwtPlotZoomer::zoomStack() const
00193 {
00194     return d_data->zoomStack;
00195 }
00196 
00201 QwtZoomStack &QwtPlotZoomer::zoomStack() 
00202 {
00203     return d_data->zoomStack;
00204 }
00205 
00210 QwtDoubleRect QwtPlotZoomer::zoomBase() const
00211 {
00212     return d_data->zoomStack[0];
00213 }
00214 
00228 void QwtPlotZoomer::setZoomBase()
00229 {
00230     const QwtPlot *plt = plot();
00231     if ( !plt )
00232         return;
00233 
00234     d_data->zoomStack.clear();
00235     d_data->zoomStack.push(scaleRect());
00236     d_data->zoomRectIndex = 0;
00237 
00238     rescale();
00239 }
00240 
00251 void QwtPlotZoomer::setZoomBase(const QwtDoubleRect &base)
00252 {
00253     const QwtPlot *plt = plot();
00254     if ( !plt )
00255         return;
00256 
00257     const QwtDoubleRect sRect = scaleRect();
00258     const QwtDoubleRect bRect = base | sRect;
00259 
00260     d_data->zoomStack.clear();
00261     d_data->zoomStack.push(bRect);
00262     d_data->zoomRectIndex = 0;
00263 
00264     if ( base != sRect )
00265     {
00266         d_data->zoomStack.push(sRect);
00267         d_data->zoomRectIndex++;
00268     }
00269 
00270     rescale();
00271 }
00272 
00278 QwtDoubleRect QwtPlotZoomer::zoomRect() const
00279 {
00280     return d_data->zoomStack[d_data->zoomRectIndex];
00281 }
00282 
00286 uint QwtPlotZoomer::zoomRectIndex() const
00287 {
00288     return d_data->zoomRectIndex;
00289 }
00290 
00301 void QwtPlotZoomer::zoom(const QwtDoubleRect &rect)
00302 {   
00303     if ( d_data->maxStackDepth >= 0 && int(d_data->zoomRectIndex) >= d_data->maxStackDepth )
00304         return;
00305 
00306     const QwtDoubleRect zoomRect = d_data->zoomStack[0] & rect.normalized();
00307     if ( zoomRect != d_data->zoomStack[d_data->zoomRectIndex] )
00308     {
00309         for ( uint i = int(d_data->zoomStack.count()) - 1; i > d_data->zoomRectIndex; i-- )
00310             (void)d_data->zoomStack.pop();
00311 
00312         d_data->zoomStack.push(zoomRect);
00313         d_data->zoomRectIndex++;
00314 
00315         rescale();
00316     }
00317 }
00318 
00329 void QwtPlotZoomer::zoom(int offset)
00330 {
00331     if ( offset == 0 )
00332         d_data->zoomRectIndex = 0;
00333     else
00334     {
00335         int newIndex = d_data->zoomRectIndex + offset;
00336         newIndex = qwtMax(0, newIndex);
00337         newIndex = qwtMin(int(d_data->zoomStack.count()) - 1, newIndex);
00338 
00339         d_data->zoomRectIndex = uint(newIndex);
00340     }
00341 
00342     rescale();
00343 }
00344 
00351 void QwtPlotZoomer::rescale()
00352 {
00353     QwtPlot *plt = plot();
00354     if ( !plt )
00355         return;
00356 
00357     const QwtDoubleRect &rect = d_data->zoomStack[d_data->zoomRectIndex];
00358     if ( rect != scaleRect() )
00359     {
00360         const bool doReplot = plt->autoReplot();
00361         plt->setAutoReplot(false);
00362 
00363         plt->setAxisScale(xAxis(), rect.left(), rect.right());
00364         plt->setAxisScale(yAxis(), rect.top(), rect.bottom());
00365 
00366         plt->setAutoReplot(doReplot);
00367 
00368         plt->replot();
00369     }
00370 }
00371 
00379 void QwtPlotZoomer::setAxis(int xAxis, int yAxis)
00380 {
00381     if ( xAxis != QwtPlotPicker::xAxis() || yAxis != QwtPlotPicker::yAxis() )
00382     {
00383         QwtPlotPicker::setAxis(xAxis, yAxis);
00384         setZoomBase(scaleRect());
00385     }
00386 }
00387 
00398 void QwtPlotZoomer::widgetMouseReleaseEvent(QMouseEvent *me)
00399 {
00400     if ( mouseMatch(MouseSelect2, me) )
00401         zoom(0);
00402     else if ( mouseMatch(MouseSelect3, me) )
00403         zoom(-1);
00404     else if ( mouseMatch(MouseSelect6, me) )
00405         zoom(+1);
00406     else 
00407         QwtPlotPicker::widgetMouseReleaseEvent(me);
00408 }
00409 
00421 void QwtPlotZoomer::widgetKeyPressEvent(QKeyEvent *ke)
00422 {
00423     if ( !isActive() )
00424     {
00425         if ( keyMatch(KeyUndo, ke) )
00426             zoom(-1);
00427         else if ( keyMatch(KeyRedo, ke) )
00428             zoom(+1);
00429         else if ( keyMatch(KeyHome, ke) )
00430             zoom(0);
00431     }
00432 
00433     QwtPlotPicker::widgetKeyPressEvent(ke);
00434 }
00435 
00444 void QwtPlotZoomer::moveBy(double dx, double dy)
00445 {
00446     const QwtDoubleRect &rect = d_data->zoomStack[d_data->zoomRectIndex];
00447     move(rect.left() + dx, rect.top() + dy);
00448 }
00449 
00459 void QwtPlotZoomer::move(double x, double y)
00460 {
00461     x = qwtMax(x, zoomBase().left());
00462     x = qwtMin(x, zoomBase().right() - zoomRect().width());
00463 
00464     y = qwtMax(y, zoomBase().top());
00465     y = qwtMin(y, zoomBase().bottom() - zoomRect().height());
00466 
00467     if ( x != zoomRect().left() || y != zoomRect().top() )
00468     {
00469         d_data->zoomStack[d_data->zoomRectIndex].moveTo(x, y);
00470         rescale();
00471     }
00472 }
00473 
00485 bool QwtPlotZoomer::accept(SelectedPoints &pa) const
00486 {
00487     if ( pa.count() < 2 )
00488         return false;
00489 
00490     QRect rect = QRect(pa[0], pa[int(pa.count()) - 1]);
00491 #if QT_VERSION < 0x040000
00492     rect = rect.normalize();
00493 #else
00494     rect = rect.normalized();
00495 #endif
00496 
00497     const int minSize = 2;
00498     if (rect.width() < minSize && rect.height() < minSize )
00499         return false; 
00500 
00501     const int minZoomSize = 11;
00502 
00503     const QPoint center = rect.center();
00504     rect.setSize(rect.size().expandedTo(QSize(minZoomSize, minZoomSize)));
00505     rect.moveCenter(center);
00506 
00507     pa.resize(2);
00508     pa[0] = rect.topLeft();
00509     pa[1] = rect.bottomRight();
00510 
00511     return true;
00512 }
00513 
00522 QwtDoubleSize QwtPlotZoomer::minZoomSize() const
00523 {
00524     char f;
00525     int fw, xprecision, yprecision;
00526 
00527     plot()->axisLabelFormat(xAxis(), f, xprecision, fw);
00528     plot()->axisLabelFormat(yAxis(), f, yprecision, fw);
00529 
00530     return QwtDoubleSize(
00531         d_data->zoomStack[0].width() / pow(10.0, xprecision - 1),
00532         d_data->zoomStack[0].height() / pow(10.0, yprecision - 1)
00533     );
00534 }
00535 
00542 void QwtPlotZoomer::begin()
00543 {
00544     if ( d_data->maxStackDepth >= 0 )
00545     {
00546         if ( d_data->zoomRectIndex >= uint(d_data->maxStackDepth) )
00547             return;
00548     }
00549 
00550     const QwtDoubleSize minSize = minZoomSize();
00551     if ( minSize.isValid() )
00552     {
00553         const QwtDoubleSize sz = 
00554             d_data->zoomStack[d_data->zoomRectIndex].size() * 0.9999;
00555 
00556         if ( minSize.width() >= sz.width() &&
00557             minSize.height() >= sz.height() )
00558         {
00559             return;
00560         }
00561     }
00562 
00563     QwtPlotPicker::begin();
00564 }
00565 
00573 bool QwtPlotZoomer::end(bool ok)
00574 {
00575     ok = QwtPlotPicker::end(ok);
00576     if (!ok)
00577         return false;
00578 
00579     QwtPlot *plot = QwtPlotZoomer::plot();
00580     if ( !plot )
00581         return false;
00582 
00583     const SelectedPoints &pa = selection();
00584     if ( pa.count() < 2 )
00585         return false;
00586 
00587     QRect rect = QRect(pa[0], pa[int(pa.count() - 1)]);
00588 #if QT_VERSION < 0x040000
00589     rect = rect.normalize();
00590 #else
00591     rect = rect.normalized();
00592 #endif
00593 
00594 
00595     QwtDoubleRect zoomRect = invTransform(rect).normalized();
00596 
00597     const QwtDoublePoint center = zoomRect.center();
00598     zoomRect.setSize(zoomRect.size().expandedTo(minZoomSize()));
00599     zoomRect.moveCenter(center);
00600 
00601     zoom(zoomRect);
00602     emit zoomed(zoomRect);
00603 
00604     return true;
00605 }
00606 
00618 void QwtPlotZoomer::setSelectionFlags(int flags)
00619 {
00620     // we accept only rects
00621     flags &= ~(PointSelection | PolygonSelection);
00622     flags |= RectSelection;
00623 
00624     QwtPlotPicker::setSelectionFlags(flags);
00625 }

Generated on Wed Aug 31 23:02:29 2005 for Qwt User's Guide by  doxygen 1.4.1