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() )
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())->lowerBound() >
00400 plt->axisScaleDiv(xAxis())->upperBound() )
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())->lowerBound() >
00410 plt->axisScaleDiv(yAxis())->upperBound() )
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
00664 flags &= ~(PointSelection | PolygonSelection);
00665 flags |= RectSelection;
00666
00667 QwtPlotPicker::setSelectionFlags(flags);
00668 }