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 #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 
00054 QwtPlotZoomer::QwtPlotZoomer(QwtPlotCanvas *canvas):
00055     QwtPlotPicker(canvas)
00056 {
00057     if ( canvas )
00058         init();
00059 }
00060 
00081 QwtPlotZoomer::QwtPlotZoomer(int xAxis, int yAxis,
00082         QwtPlotCanvas *canvas):
00083     QwtPlotPicker(xAxis, yAxis, canvas)
00084 {
00085     if ( canvas )
00086     {
00087         init();
00088     }
00089 }
00090 
00114 QwtPlotZoomer::QwtPlotZoomer(int xAxis, int yAxis, int selectionFlags,
00115         DisplayMode trackerMode, QwtPlotCanvas *canvas):
00116     QwtPlotPicker(xAxis, yAxis,canvas)
00117 {
00118     if ( canvas )
00119     {
00120         init(selectionFlags, trackerMode);
00121     }
00122 }
00123 
00125 void QwtPlotZoomer::init(int selectionFlags, DisplayMode trackerMode)
00126 {
00127     d_data = new PrivateData;
00128 
00129     d_data->maxStackDepth = -1;
00130 
00131     setSelectionFlags(selectionFlags);
00132     setTrackerMode(trackerMode);
00133     setRubberBand(RectRubberBand);
00134 
00135     setZoomBase(scaleRect());
00136 }
00137 
00138 QwtPlotZoomer::~QwtPlotZoomer()
00139 {
00140     delete d_data;
00141 }
00142 
00154 void QwtPlotZoomer::setMaxStackDepth(int depth)
00155 {
00156     d_data->maxStackDepth = depth;
00157 
00158     if ( depth >= 0 )
00159     {
00160         // unzoom if the current depth is below d_data->maxStackDepth
00161 
00162         const int zoomOut = 
00163             int(d_data->zoomStack.count()) - 1 - depth; // -1 for the zoom base
00164 
00165         if ( zoomOut > 0 )
00166         {
00167             zoom(-zoomOut);
00168             for ( int i = int(d_data->zoomStack.count()) - 1; 
00169                 i > int(d_data->zoomRectIndex); i-- )
00170             {
00171                 (void)d_data->zoomStack.pop(); // remove trailing rects
00172             }
00173         }
00174     }
00175 }
00176 
00181 int QwtPlotZoomer::maxStackDepth() const
00182 {
00183     return d_data->maxStackDepth;
00184 }
00185 
00190 const QwtZoomStack &QwtPlotZoomer::zoomStack() const
00191 {
00192     return d_data->zoomStack;
00193 }
00194 
00199 QwtDoubleRect QwtPlotZoomer::zoomBase() const
00200 {
00201     return d_data->zoomStack[0];
00202 }
00203 
00217 void QwtPlotZoomer::setZoomBase()
00218 {
00219     const QwtPlot *plt = plot();
00220     if ( !plt )
00221         return;
00222 
00223     d_data->zoomStack.clear();
00224     d_data->zoomStack.push(scaleRect());
00225     d_data->zoomRectIndex = 0;
00226 
00227     rescale();
00228 }
00229 
00240 void QwtPlotZoomer::setZoomBase(const QwtDoubleRect &base)
00241 {
00242     const QwtPlot *plt = plot();
00243     if ( !plt )
00244         return;
00245 
00246     const QwtDoubleRect sRect = scaleRect();
00247     const QwtDoubleRect bRect = base | sRect;
00248 
00249     d_data->zoomStack.clear();
00250     d_data->zoomStack.push(bRect);
00251     d_data->zoomRectIndex = 0;
00252 
00253     if ( base != sRect )
00254     {
00255         d_data->zoomStack.push(sRect);
00256         d_data->zoomRectIndex++;
00257     }
00258 
00259     rescale();
00260 }
00261 
00267 QwtDoubleRect QwtPlotZoomer::zoomRect() const
00268 {
00269     return d_data->zoomStack[d_data->zoomRectIndex];
00270 }
00271 
00275 uint QwtPlotZoomer::zoomRectIndex() const
00276 {
00277     return d_data->zoomRectIndex;
00278 }
00279 
00290 void QwtPlotZoomer::zoom(const QwtDoubleRect &rect)
00291 {   
00292     if ( d_data->maxStackDepth >= 0 && 
00293         int(d_data->zoomRectIndex) >= d_data->maxStackDepth )
00294     {
00295         return;
00296     }
00297 
00298     const QwtDoubleRect zoomRect = d_data->zoomStack[0] & rect.normalized();
00299     if ( zoomRect != d_data->zoomStack[d_data->zoomRectIndex] )
00300     {
00301         for ( uint i = int(d_data->zoomStack.count()) - 1; 
00302            i > d_data->zoomRectIndex; i-- )
00303         {
00304             (void)d_data->zoomStack.pop();
00305         }
00306 
00307         d_data->zoomStack.push(zoomRect);
00308         d_data->zoomRectIndex++;
00309 
00310         rescale();
00311     }
00312 }
00313 
00324 void QwtPlotZoomer::zoom(int offset)
00325 {
00326     if ( offset == 0 )
00327         d_data->zoomRectIndex = 0;
00328     else
00329     {
00330         int newIndex = d_data->zoomRectIndex + offset;
00331         newIndex = qwtMax(0, newIndex);
00332         newIndex = qwtMin(int(d_data->zoomStack.count()) - 1, newIndex);
00333 
00334         d_data->zoomRectIndex = uint(newIndex);
00335     }
00336 
00337     rescale();
00338 }
00339 
00346 void QwtPlotZoomer::rescale()
00347 {
00348     QwtPlot *plt = plot();
00349     if ( !plt )
00350         return;
00351 
00352     const QwtDoubleRect &rect = d_data->zoomStack[d_data->zoomRectIndex];
00353     if ( rect != scaleRect() )
00354     {
00355         const bool doReplot = plt->autoReplot();
00356         plt->setAutoReplot(false);
00357 
00358         double x1 = rect.left();
00359         double x2 = rect.right();
00360         if ( plt->axisScaleDiv(xAxis())->lBound() > 
00361             plt->axisScaleDiv(xAxis())->hBound() )
00362         {
00363             qSwap(x1, x2);
00364         }
00365 
00366         plt->setAxisScale(xAxis(), x1, x2);
00367 
00368         double y1 = rect.top();
00369         double y2 = rect.bottom();
00370         if ( plt->axisScaleDiv(yAxis())->lBound() > 
00371             plt->axisScaleDiv(yAxis())->hBound() )
00372         {
00373             qSwap(y1, y2);
00374         }
00375         plt->setAxisScale(yAxis(), y1, y2);
00376 
00377         plt->setAutoReplot(doReplot);
00378 
00379         plt->replot();
00380     }
00381 }
00382 
00390 void QwtPlotZoomer::setAxis(int xAxis, int yAxis)
00391 {
00392     if ( xAxis != QwtPlotPicker::xAxis() || yAxis != QwtPlotPicker::yAxis() )
00393     {
00394         QwtPlotPicker::setAxis(xAxis, yAxis);
00395         setZoomBase(scaleRect());
00396     }
00397 }
00398 
00409 void QwtPlotZoomer::widgetMouseReleaseEvent(QMouseEvent *me)
00410 {
00411     if ( mouseMatch(MouseSelect2, me) )
00412         zoom(0);
00413     else if ( mouseMatch(MouseSelect3, me) )
00414         zoom(-1);
00415     else if ( mouseMatch(MouseSelect6, me) )
00416         zoom(+1);
00417     else 
00418         QwtPlotPicker::widgetMouseReleaseEvent(me);
00419 }
00420 
00432 void QwtPlotZoomer::widgetKeyPressEvent(QKeyEvent *ke)
00433 {
00434     if ( !isActive() )
00435     {
00436         if ( keyMatch(KeyUndo, ke) )
00437             zoom(-1);
00438         else if ( keyMatch(KeyRedo, ke) )
00439             zoom(+1);
00440         else if ( keyMatch(KeyHome, ke) )
00441             zoom(0);
00442     }
00443 
00444     QwtPlotPicker::widgetKeyPressEvent(ke);
00445 }
00446 
00455 void QwtPlotZoomer::moveBy(double dx, double dy)
00456 {
00457     const QwtDoubleRect &rect = d_data->zoomStack[d_data->zoomRectIndex];
00458     move(rect.left() + dx, rect.top() + dy);
00459 }
00460 
00470 void QwtPlotZoomer::move(double x, double y)
00471 {
00472     x = qwtMax(x, zoomBase().left());
00473     x = qwtMin(x, zoomBase().right() - zoomRect().width());
00474 
00475     y = qwtMax(y, zoomBase().top());
00476     y = qwtMin(y, zoomBase().bottom() - zoomRect().height());
00477 
00478     if ( x != zoomRect().left() || y != zoomRect().top() )
00479     {
00480         d_data->zoomStack[d_data->zoomRectIndex].moveTo(x, y);
00481         rescale();
00482     }
00483 }
00484 
00496 bool QwtPlotZoomer::accept(SelectedPoints &pa) const
00497 {
00498     if ( pa.count() < 2 )
00499         return false;
00500 
00501     QRect rect = QRect(pa[0], pa[int(pa.count()) - 1]);
00502 #if QT_VERSION < 0x040000
00503     rect = rect.normalize();
00504 #else
00505     rect = rect.normalized();
00506 #endif
00507 
00508     const int minSize = 2;
00509     if (rect.width() < minSize && rect.height() < minSize )
00510         return false; 
00511 
00512     const int minZoomSize = 11;
00513 
00514     const QPoint center = rect.center();
00515     rect.setSize(rect.size().expandedTo(QSize(minZoomSize, minZoomSize)));
00516     rect.moveCenter(center);
00517 
00518     pa.resize(2);
00519     pa[0] = rect.topLeft();
00520     pa[1] = rect.bottomRight();
00521 
00522     return true;
00523 }
00524 
00530 QwtDoubleSize QwtPlotZoomer::minZoomSize() const
00531 {
00532     return QwtDoubleSize(
00533         d_data->zoomStack[0].width() / 10e4,
00534         d_data->zoomStack[0].height() / 10e4
00535     );
00536 }
00537 
00544 void QwtPlotZoomer::begin()
00545 {
00546     if ( d_data->maxStackDepth >= 0 )
00547     {
00548         if ( d_data->zoomRectIndex >= uint(d_data->maxStackDepth) )
00549             return;
00550     }
00551 
00552     const QwtDoubleSize minSize = minZoomSize();
00553     if ( minSize.isValid() )
00554     {
00555         const QwtDoubleSize sz = 
00556             d_data->zoomStack[d_data->zoomRectIndex].size() * 0.9999;
00557 
00558         if ( minSize.width() >= sz.width() &&
00559             minSize.height() >= sz.height() )
00560         {
00561             return;
00562         }
00563     }
00564 
00565     QwtPlotPicker::begin();
00566 }
00567 
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 SelectedPoints &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     emit zoomed(zoomRect);
00605 
00606     return true;
00607 }
00608 
00620 void QwtPlotZoomer::setSelectionFlags(int flags)
00621 {
00622     // we accept only rects
00623     flags &= ~(PointSelection | PolygonSelection);
00624     flags |= RectSelection;
00625 
00626     QwtPlotPicker::setSelectionFlags(flags);
00627 }

Generated on Mon Jan 30 22:16:26 2006 for Qwt User's Guide by  doxygen 1.4.4