00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
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
00152
00153 const int zoomOut =
00154 int(d_data->zoomStack.count()) - 1 - depth;
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();
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
00658 flags &= ~(PointSelection | PolygonSelection);
00659 flags |= RectSelection;
00660
00661 QwtPlotPicker::setSelectionFlags(flags);
00662 }