00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "qwt_plot_zoomer.h"
00011 #include "qwt_plot.h"
00012 #include "qwt_scale_div.h"
00013 #include "qwt_scale_map.h"
00014 #include "qwt_interval.h"
00015 #include "qwt_picker_machine.h"
00016
00017 #include <qstack.h>
00018
00019 static QwtInterval qwtExpandedZoomInterval( double v1, double v2,
00020 double minRange, const QwtTransform* transform )
00021 {
00022 double min = v1;
00023 double max = v2;
00024
00025 if ( max - min < minRange )
00026 {
00027 min = 0.5 * ( min + max - minRange );
00028 max = min + minRange;
00029
00030 if ( transform )
00031 {
00032
00033
00034
00035 double minBounded = transform->bounded( min );
00036 double maxBounded = transform->bounded( max );
00037
00038 if ( minBounded != min )
00039 {
00040 maxBounded = transform->bounded( minBounded + minRange );
00041 }
00042 else if ( maxBounded != max )
00043 {
00044 minBounded = transform->bounded( maxBounded - minRange );
00045 }
00046
00047 min = minBounded;
00048 max = maxBounded;
00049 }
00050 }
00051
00052 return QwtInterval( min, max );
00053 }
00054
00055 static QRectF qwtExpandedZoomRect( const QRectF &zoomRect, const QSizeF &minSize,
00056 const QwtTransform* transformX, const QwtTransform* transformY )
00057 {
00058 QRectF r = zoomRect;
00059
00060 if ( minSize.width() > r.width() )
00061 {
00062 const QwtInterval intv = qwtExpandedZoomInterval(
00063 r.left(), r.right(), minSize.width(), transformX );
00064
00065 r.setLeft( intv.minValue() );
00066 r.setRight( intv.maxValue() );
00067 }
00068
00069 if ( minSize.height() > r.height() )
00070 {
00071 const QwtInterval intv = qwtExpandedZoomInterval(
00072 zoomRect.top(), zoomRect.bottom(), minSize.height(), transformY );
00073
00074 r.setTop( intv.minValue() );
00075 r.setBottom( intv.maxValue() );
00076 }
00077
00078 return r;
00079 }
00080
00081 class QwtPlotZoomer::PrivateData
00082 {
00083 public:
00084 uint zoomRectIndex;
00085 QStack<QRectF> zoomStack;
00086
00087 int maxStackDepth;
00088 };
00089
00109 QwtPlotZoomer::QwtPlotZoomer( QWidget *canvas, bool doReplot ):
00110 QwtPlotPicker( canvas )
00111 {
00112 if ( canvas )
00113 init( doReplot );
00114 }
00115
00133 QwtPlotZoomer::QwtPlotZoomer( int xAxis, int yAxis,
00134 QWidget *canvas, bool doReplot ):
00135 QwtPlotPicker( xAxis, yAxis, canvas )
00136 {
00137 if ( canvas )
00138 init( doReplot );
00139 }
00140
00142 void QwtPlotZoomer::init( bool doReplot )
00143 {
00144 d_data = new PrivateData;
00145
00146 d_data->maxStackDepth = -1;
00147
00148 setTrackerMode( ActiveOnly );
00149 setRubberBand( RectRubberBand );
00150 setStateMachine( new QwtPickerDragRectMachine() );
00151
00152 if ( doReplot && plot() )
00153 plot()->replot();
00154
00155 setZoomBase( scaleRect() );
00156 }
00157
00158 QwtPlotZoomer::~QwtPlotZoomer()
00159 {
00160 delete d_data;
00161 }
00162
00174 void QwtPlotZoomer::setMaxStackDepth( int depth )
00175 {
00176 d_data->maxStackDepth = depth;
00177
00178 if ( depth >= 0 )
00179 {
00180
00181
00182 const int zoomOut =
00183 d_data->zoomStack.count() - 1 - depth;
00184
00185 if ( zoomOut > 0 )
00186 {
00187 zoom( -zoomOut );
00188 for ( int i = d_data->zoomStack.count() - 1;
00189 i > int( d_data->zoomRectIndex ); i-- )
00190 {
00191 ( void )d_data->zoomStack.pop();
00192 }
00193 }
00194 }
00195 }
00196
00201 int QwtPlotZoomer::maxStackDepth() const
00202 {
00203 return d_data->maxStackDepth;
00204 }
00205
00212 const QStack<QRectF> &QwtPlotZoomer::zoomStack() const
00213 {
00214 return d_data->zoomStack;
00215 }
00216
00221 QRectF QwtPlotZoomer::zoomBase() const
00222 {
00223 return d_data->zoomStack[0];
00224 }
00225
00235 void QwtPlotZoomer::setZoomBase( bool doReplot )
00236 {
00237 QwtPlot *plt = plot();
00238 if ( plt == NULL )
00239 return;
00240
00241 if ( doReplot )
00242 plt->replot();
00243
00244 d_data->zoomStack.clear();
00245 d_data->zoomStack.push( scaleRect() );
00246 d_data->zoomRectIndex = 0;
00247
00248 rescale();
00249 }
00250
00261 void QwtPlotZoomer::setZoomBase( const QRectF &base )
00262 {
00263 const QwtPlot *plt = plot();
00264 if ( !plt )
00265 return;
00266
00267 const QRectF sRect = scaleRect();
00268 const QRectF bRect = base | sRect;
00269
00270 d_data->zoomStack.clear();
00271 d_data->zoomStack.push( bRect );
00272 d_data->zoomRectIndex = 0;
00273
00274 if ( base != sRect )
00275 {
00276 d_data->zoomStack.push( sRect );
00277 d_data->zoomRectIndex++;
00278 }
00279
00280 rescale();
00281 }
00282
00287 QRectF QwtPlotZoomer::zoomRect() const
00288 {
00289 return d_data->zoomStack[d_data->zoomRectIndex];
00290 }
00291
00295 uint QwtPlotZoomer::zoomRectIndex() const
00296 {
00297 return d_data->zoomRectIndex;
00298 }
00299
00310 void QwtPlotZoomer::zoom( const QRectF &rect )
00311 {
00312 if ( d_data->maxStackDepth >= 0 &&
00313 int( d_data->zoomRectIndex ) >= d_data->maxStackDepth )
00314 {
00315 return;
00316 }
00317
00318 const QRectF zoomRect = rect.normalized();
00319 if ( zoomRect != d_data->zoomStack[d_data->zoomRectIndex] )
00320 {
00321 for ( uint i = d_data->zoomStack.count() - 1;
00322 i > d_data->zoomRectIndex; i-- )
00323 {
00324 ( void )d_data->zoomStack.pop();
00325 }
00326
00327 d_data->zoomStack.push( zoomRect );
00328 d_data->zoomRectIndex++;
00329
00330 rescale();
00331
00332 Q_EMIT zoomed( zoomRect );
00333 }
00334 }
00335
00347 void QwtPlotZoomer::zoom( int offset )
00348 {
00349 int newIndex;
00350
00351 if ( offset == 0 )
00352 {
00353 newIndex = 0;
00354 }
00355 else
00356 {
00357 newIndex = d_data->zoomRectIndex + offset;
00358 newIndex = qBound( 0, newIndex, d_data->zoomStack.count() - 1 );
00359 }
00360
00361 if ( newIndex != static_cast<int>( d_data->zoomRectIndex ) )
00362 {
00363 d_data->zoomRectIndex = newIndex;
00364 rescale();
00365 Q_EMIT zoomed( zoomRect() );
00366 }
00367 }
00368
00383 void QwtPlotZoomer::setZoomStack(
00384 const QStack<QRectF> &zoomStack, int zoomRectIndex )
00385 {
00386 if ( zoomStack.isEmpty() )
00387 return;
00388
00389 if ( d_data->maxStackDepth >= 0 &&
00390 zoomStack.count() > d_data->maxStackDepth )
00391 {
00392 return;
00393 }
00394
00395 if ( zoomRectIndex < 0 || zoomRectIndex > zoomStack.count() )
00396 zoomRectIndex = zoomStack.count() - 1;
00397
00398 const bool doRescale = zoomStack[zoomRectIndex] != zoomRect();
00399
00400 d_data->zoomStack = zoomStack;
00401 d_data->zoomRectIndex = uint( zoomRectIndex );
00402
00403 if ( doRescale )
00404 {
00405 rescale();
00406 Q_EMIT zoomed( zoomRect() );
00407 }
00408 }
00409
00416 void QwtPlotZoomer::rescale()
00417 {
00418 QwtPlot *plt = plot();
00419 if ( !plt )
00420 return;
00421
00422 const QRectF &rect = d_data->zoomStack[d_data->zoomRectIndex];
00423 if ( rect != scaleRect() )
00424 {
00425 const bool doReplot = plt->autoReplot();
00426 plt->setAutoReplot( false );
00427
00428 double x1 = rect.left();
00429 double x2 = rect.right();
00430 if ( !plt->axisScaleDiv( xAxis() ).isIncreasing() )
00431 qSwap( x1, x2 );
00432
00433 plt->setAxisScale( xAxis(), x1, x2 );
00434
00435 double y1 = rect.top();
00436 double y2 = rect.bottom();
00437 if ( !plt->axisScaleDiv( yAxis() ).isIncreasing() )
00438 qSwap( y1, y2 );
00439
00440 plt->setAxisScale( yAxis(), y1, y2 );
00441
00442 plt->setAutoReplot( doReplot );
00443
00444 plt->replot();
00445 }
00446 }
00447
00455 void QwtPlotZoomer::setAxis( int xAxis, int yAxis )
00456 {
00457 if ( xAxis != QwtPlotPicker::xAxis() || yAxis != QwtPlotPicker::yAxis() )
00458 {
00459 QwtPlotPicker::setAxis( xAxis, yAxis );
00460 setZoomBase( scaleRect() );
00461 }
00462 }
00463
00474 void QwtPlotZoomer::widgetMouseReleaseEvent( QMouseEvent *me )
00475 {
00476 if ( mouseMatch( MouseSelect2, me ) )
00477 zoom( 0 );
00478 else if ( mouseMatch( MouseSelect3, me ) )
00479 zoom( -1 );
00480 else if ( mouseMatch( MouseSelect6, me ) )
00481 zoom( +1 );
00482 else
00483 QwtPlotPicker::widgetMouseReleaseEvent( me );
00484 }
00485
00497 void QwtPlotZoomer::widgetKeyPressEvent( QKeyEvent *ke )
00498 {
00499 if ( !isActive() )
00500 {
00501 if ( keyMatch( KeyUndo, ke ) )
00502 zoom( -1 );
00503 else if ( keyMatch( KeyRedo, ke ) )
00504 zoom( +1 );
00505 else if ( keyMatch( KeyHome, ke ) )
00506 zoom( 0 );
00507 }
00508
00509 QwtPlotPicker::widgetKeyPressEvent( ke );
00510 }
00511
00520 void QwtPlotZoomer::moveBy( double dx, double dy )
00521 {
00522 const QRectF &rect = d_data->zoomStack[d_data->zoomRectIndex];
00523 moveTo( QPointF( rect.left() + dx, rect.top() + dy ) );
00524 }
00525
00534 void QwtPlotZoomer::moveTo( const QPointF &pos )
00535 {
00536 double x = pos.x();
00537 double y = pos.y();
00538
00539 if ( x < zoomBase().left() )
00540 x = zoomBase().left();
00541 if ( x > zoomBase().right() - zoomRect().width() )
00542 x = zoomBase().right() - zoomRect().width();
00543
00544 if ( y < zoomBase().top() )
00545 y = zoomBase().top();
00546 if ( y > zoomBase().bottom() - zoomRect().height() )
00547 y = zoomBase().bottom() - zoomRect().height();
00548
00549 if ( x != zoomRect().left() || y != zoomRect().top() )
00550 {
00551 d_data->zoomStack[d_data->zoomRectIndex].moveTo( x, y );
00552 rescale();
00553 }
00554 }
00555
00567 bool QwtPlotZoomer::accept( QPolygon &pa ) const
00568 {
00569 if ( pa.count() < 2 )
00570 return false;
00571
00572 QRect rect = QRect( pa.first(), pa.last() );
00573 rect = rect.normalized();
00574
00575 const int minSize = 2;
00576 if ( rect.width() < minSize && rect.height() < minSize )
00577 return false;
00578
00579 const int minZoomSize = 11;
00580
00581 const QPoint center = rect.center();
00582 rect.setSize( rect.size().expandedTo( QSize( minZoomSize, minZoomSize ) ) );
00583 rect.moveCenter( center );
00584
00585 pa.resize( 2 );
00586 pa[0] = rect.topLeft();
00587 pa[1] = rect.bottomRight();
00588
00589 return true;
00590 }
00591
00597 QSizeF QwtPlotZoomer::minZoomSize() const
00598 {
00599 return QSizeF( d_data->zoomStack[0].width() / 10e4,
00600 d_data->zoomStack[0].height() / 10e4 );
00601 }
00602
00609 void QwtPlotZoomer::begin()
00610 {
00611 if ( d_data->maxStackDepth >= 0 )
00612 {
00613 if ( d_data->zoomRectIndex >= uint( d_data->maxStackDepth ) )
00614 return;
00615 }
00616
00617 const QSizeF minSize = minZoomSize();
00618 if ( minSize.isValid() )
00619 {
00620 const QSizeF sz =
00621 d_data->zoomStack[d_data->zoomRectIndex].size() * 0.9999;
00622
00623 if ( minSize.width() >= sz.width() &&
00624 minSize.height() >= sz.height() )
00625 {
00626 return;
00627 }
00628 }
00629
00630 QwtPlotPicker::begin();
00631 }
00632
00643 bool QwtPlotZoomer::end( bool ok )
00644 {
00645 ok = QwtPlotPicker::end( ok );
00646 if ( !ok )
00647 return false;
00648
00649 QwtPlot *plot = QwtPlotZoomer::plot();
00650 if ( !plot )
00651 return false;
00652
00653 const QPolygon &pa = selection();
00654 if ( pa.count() < 2 )
00655 return false;
00656
00657 QRect rect = QRect( pa.first(), pa.last() );
00658 rect = rect.normalized();
00659
00660 const QwtScaleMap xMap = plot->canvasMap( xAxis() );
00661 const QwtScaleMap yMap = plot->canvasMap( yAxis() );
00662
00663 QRectF zoomRect = QwtScaleMap::invTransform( xMap, yMap, rect ).normalized();
00664
00665 zoomRect = qwtExpandedZoomRect( zoomRect, minZoomSize(),
00666 xMap.transformation(), yMap.transformation() );
00667
00668 zoom( zoomRect );
00669
00670 return true;
00671 }