qwt_plot_zoomer.cpp 14.8 KB
Newer Older
pixhawk's avatar
pixhawk committed
1 2 3 4 5 6 7 8 9 10
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
 * Qwt Widget Library
 * Copyright (C) 1997   Josef Wilgen
 * Copyright (C) 2002   Uwe Rathmann
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the Qwt License, Version 1.0
 *****************************************************************************/

#include "qwt_plot_zoomer.h"
Bryant's avatar
Bryant committed
11
#include "qwt_plot.h"
pixhawk's avatar
pixhawk committed
12
#include "qwt_scale_div.h"
Bryant's avatar
Bryant committed
13 14
#include "qwt_picker_machine.h"
#include <qalgorithms.h>
pixhawk's avatar
pixhawk committed
15 16 17 18 19

class QwtPlotZoomer::PrivateData
{
public:
    uint zoomRectIndex;
Bryant's avatar
Bryant committed
20
    QStack<QRectF> zoomStack;
pixhawk's avatar
pixhawk committed
21 22 23 24 25 26 27 28 29 30 31 32

    int maxStackDepth;
};

/*!
  \brief Create a zoomer for a plot canvas.

  The zoomer is set to those x- and y-axis of the parent plot of the
  canvas that are enabled. If both or no x-axis are enabled, the picker
  is set to QwtPlot::xBottom. If both or no y-axis are
  enabled, it is set to QwtPlot::yLeft.

Bryant's avatar
Bryant committed
33 34 35
  The zoomer is initialized with a QwtPickerDragRectMachine,
  the tracker mode is set to QwtPicker::ActiveOnly and the rubber band
  is set to QwtPicker::RectRubberBand
pixhawk's avatar
pixhawk committed
36 37

  \param canvas Plot canvas to observe, also the parent object
Bryant's avatar
Bryant committed
38
  \param doReplot Call QwtPlot::replot() for the attached plot before initializing
39
                  the zoomer with its scales. This might be necessary,
pixhawk's avatar
pixhawk committed
40 41 42 43
                  when the plot is in a state with pending scale changes.

  \sa QwtPlot::autoReplot(), QwtPlot::replot(), setZoomBase()
*/
Bryant's avatar
Bryant committed
44 45
QwtPlotZoomer::QwtPlotZoomer( QWidget *canvas, bool doReplot ):
    QwtPlotPicker( canvas )
pixhawk's avatar
pixhawk committed
46 47
{
    if ( canvas )
Bryant's avatar
Bryant committed
48
        init( doReplot );
pixhawk's avatar
pixhawk committed
49 50 51 52 53
}

/*!
  \brief Create a zoomer for a plot canvas.

Bryant's avatar
Bryant committed
54 55 56
  The zoomer is initialized with a QwtPickerDragRectMachine,
  the tracker mode is set to QwtPicker::ActiveOnly and the rubber band
  is set to QwtPicker;;RectRubberBand
pixhawk's avatar
pixhawk committed
57 58 59 60

  \param xAxis X axis of the zoomer
  \param yAxis Y axis of the zoomer
  \param canvas Plot canvas to observe, also the parent object
Bryant's avatar
Bryant committed
61
  \param doReplot Call QwtPlot::replot() for the attached plot before initializing
62
                  the zoomer with its scales. This might be necessary,
pixhawk's avatar
pixhawk committed
63 64 65 66 67
                  when the plot is in a state with pending scale changes.

  \sa QwtPlot::autoReplot(), QwtPlot::replot(), setZoomBase()
*/

Bryant's avatar
Bryant committed
68 69 70
QwtPlotZoomer::QwtPlotZoomer( int xAxis, int yAxis,
        QWidget *canvas, bool doReplot ):
    QwtPlotPicker( xAxis, yAxis, canvas )
pixhawk's avatar
pixhawk committed
71 72
{
    if ( canvas )
Bryant's avatar
Bryant committed
73
        init( doReplot );
pixhawk's avatar
pixhawk committed
74 75 76
}

//! Init the zoomer, used by the constructors
Bryant's avatar
Bryant committed
77
void QwtPlotZoomer::init( bool doReplot )
pixhawk's avatar
pixhawk committed
78 79 80 81 82
{
    d_data = new PrivateData;

    d_data->maxStackDepth = -1;

Bryant's avatar
Bryant committed
83 84 85
    setTrackerMode( ActiveOnly );
    setRubberBand( RectRubberBand );
    setStateMachine( new QwtPickerDragRectMachine() );
pixhawk's avatar
pixhawk committed
86 87 88 89

    if ( doReplot && plot() )
        plot()->replot();

Bryant's avatar
Bryant committed
90
    setZoomBase( scaleRect() );
pixhawk's avatar
pixhawk committed
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
}

QwtPlotZoomer::~QwtPlotZoomer()
{
    delete d_data;
}

/*!
  \brief Limit the number of recursive zoom operations to depth.

  A value of -1 set the depth to unlimited, 0 disables zooming.
  If the current zoom rectangle is below depth, the plot is unzoomed.

  \param depth Maximum for the stack depth
  \sa maxStackDepth()
  \note depth doesn't include the zoom base, so zoomStack().count() might be
              maxStackDepth() + 1.
*/
Bryant's avatar
Bryant committed
109
void QwtPlotZoomer::setMaxStackDepth( int depth )
pixhawk's avatar
pixhawk committed
110 111 112
{
    d_data->maxStackDepth = depth;

Bryant's avatar
Bryant committed
113 114
    if ( depth >= 0 )
    {
pixhawk's avatar
pixhawk committed
115 116
        // unzoom if the current depth is below d_data->maxStackDepth

117
        const int zoomOut =
Bryant's avatar
Bryant committed
118 119 120 121 122 123 124 125 126
            int( d_data->zoomStack.count() ) - 1 - depth; // -1 for the zoom base

        if ( zoomOut > 0 )
        {
            zoom( -zoomOut );
            for ( int i = int( d_data->zoomStack.count() ) - 1;
                i > int( d_data->zoomRectIndex ); i-- )
            {
                ( void )d_data->zoomStack.pop(); // remove trailing rects
pixhawk's avatar
pixhawk committed
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
            }
        }
    }
}

/*!
  \return Maximal depth of the zoom stack.
  \sa setMaxStackDepth()
*/
int QwtPlotZoomer::maxStackDepth() const
{
    return d_data->maxStackDepth;
}

/*!
Bryant's avatar
Bryant committed
142 143
  \return The zoom stack. zoomStack()[0] is the zoom base,
          zoomStack()[1] the first zoomed rectangle.
pixhawk's avatar
pixhawk committed
144 145 146

  \sa setZoomStack(), zoomRectIndex()
*/
Bryant's avatar
Bryant committed
147
const QStack<QRectF> &QwtPlotZoomer::zoomStack() const
pixhawk's avatar
pixhawk committed
148 149 150 151 152 153 154 155
{
    return d_data->zoomStack;
}

/*!
  \return Initial rectangle of the zoomer
  \sa setZoomBase(), zoomRect()
*/
Bryant's avatar
Bryant committed
156
QRectF QwtPlotZoomer::zoomBase() const
pixhawk's avatar
pixhawk committed
157 158 159 160 161 162 163
{
    return d_data->zoomStack[0];
}

/*!
  Reinitialized the zoom stack with scaleRect() as base.

Bryant's avatar
Bryant committed
164
  \param doReplot Call QwtPlot::replot() for the attached plot before initializing
165
                  the zoomer with its scales. This might be necessary,
pixhawk's avatar
pixhawk committed
166 167 168 169
                  when the plot is in a state with pending scale changes.

  \sa zoomBase(), scaleRect() QwtPlot::autoReplot(), QwtPlot::replot().
*/
Bryant's avatar
Bryant committed
170
void QwtPlotZoomer::setZoomBase( bool doReplot )
pixhawk's avatar
pixhawk committed
171 172 173 174 175 176 177 178 179
{
    QwtPlot *plt = plot();
    if ( plt == NULL )
        return;

    if ( doReplot )
        plt->replot();

    d_data->zoomStack.clear();
Bryant's avatar
Bryant committed
180
    d_data->zoomStack.push( scaleRect() );
pixhawk's avatar
pixhawk committed
181 182 183 184 185 186 187 188 189
    d_data->zoomRectIndex = 0;

    rescale();
}

/*!
  \brief Set the initial size of the zoomer.

  base is united with the current scaleRect() and the zoom stack is
Bryant's avatar
Bryant committed
190
  reinitialized with it as zoom base. plot is zoomed to scaleRect().
191

pixhawk's avatar
pixhawk committed
192
  \param base Zoom base
193

pixhawk's avatar
pixhawk committed
194 195
  \sa zoomBase(), scaleRect()
*/
Bryant's avatar
Bryant committed
196
void QwtPlotZoomer::setZoomBase( const QRectF &base )
pixhawk's avatar
pixhawk committed
197 198 199 200 201
{
    const QwtPlot *plt = plot();
    if ( !plt )
        return;

Bryant's avatar
Bryant committed
202 203
    const QRectF sRect = scaleRect();
    const QRectF bRect = base | sRect;
pixhawk's avatar
pixhawk committed
204 205

    d_data->zoomStack.clear();
Bryant's avatar
Bryant committed
206
    d_data->zoomStack.push( bRect );
pixhawk's avatar
pixhawk committed
207 208
    d_data->zoomRectIndex = 0;

Bryant's avatar
Bryant committed
209 210 211
    if ( base != sRect )
    {
        d_data->zoomStack.push( sRect );
pixhawk's avatar
pixhawk committed
212 213 214 215 216 217
        d_data->zoomRectIndex++;
    }

    rescale();
}

218
/*!
Bryant's avatar
Bryant committed
219
  \return Rectangle at the current position on the zoom stack.
pixhawk's avatar
pixhawk committed
220 221
  \sa zoomRectIndex(), scaleRect().
*/
Bryant's avatar
Bryant committed
222
QRectF QwtPlotZoomer::zoomRect() const
pixhawk's avatar
pixhawk committed
223 224 225 226
{
    return d_data->zoomStack[d_data->zoomRectIndex];
}

227
/*!
pixhawk's avatar
pixhawk committed
228 229 230 231 232 233 234 235 236 237 238
  \return Index of current position of zoom stack.
*/
uint QwtPlotZoomer::zoomRectIndex() const
{
    return d_data->zoomRectIndex;
}

/*!
  \brief Zoom in

  Clears all rectangles above the current position of the
Bryant's avatar
Bryant committed
239
  zoom stack and pushes the normalized rectangle on it.
pixhawk's avatar
pixhawk committed
240 241 242 243 244

  \note If the maximal stack depth is reached, zoom is ignored.
  \note The zoomed signal is emitted.
*/

Bryant's avatar
Bryant committed
245
void QwtPlotZoomer::zoom( const QRectF &rect )
246 247
{
    if ( d_data->maxStackDepth >= 0 &&
Bryant's avatar
Bryant committed
248 249
            int( d_data->zoomRectIndex ) >= d_data->maxStackDepth )
    {
pixhawk's avatar
pixhawk committed
250 251 252
        return;
    }

Bryant's avatar
Bryant committed
253 254 255 256 257 258 259
    const QRectF zoomRect = rect.normalized();
    if ( zoomRect != d_data->zoomStack[d_data->zoomRectIndex] )
    {
        for ( uint i = int( d_data->zoomStack.count() ) - 1;
           i > d_data->zoomRectIndex; i-- )
        {
            ( void )d_data->zoomStack.pop();
pixhawk's avatar
pixhawk committed
260 261
        }

Bryant's avatar
Bryant committed
262
        d_data->zoomStack.push( zoomRect );
pixhawk's avatar
pixhawk committed
263 264 265 266
        d_data->zoomRectIndex++;

        rescale();

Bryant's avatar
Bryant committed
267
        Q_EMIT zoomed( zoomRect );
pixhawk's avatar
pixhawk committed
268 269 270 271 272 273 274
    }
}

/*!
  \brief Zoom in or out

  Activate a rectangle on the zoom stack with an offset relative
Bryant's avatar
Bryant committed
275
  to the current position. Negative values of offset will zoom out,
pixhawk's avatar
pixhawk committed
276 277 278 279 280 281
  positive zoom in. A value of 0 zooms out to the zoom base.

  \param offset Offset relative to the current position of the zoom stack.
  \note The zoomed signal is emitted.
  \sa zoomRectIndex()
*/
Bryant's avatar
Bryant committed
282
void QwtPlotZoomer::zoom( int offset )
pixhawk's avatar
pixhawk committed
283 284 285
{
    if ( offset == 0 )
        d_data->zoomRectIndex = 0;
Bryant's avatar
Bryant committed
286 287
    else
    {
pixhawk's avatar
pixhawk committed
288
        int newIndex = d_data->zoomRectIndex + offset;
Bryant's avatar
Bryant committed
289 290
        newIndex = qMax( 0, newIndex );
        newIndex = qMin( int( d_data->zoomStack.count() ) - 1, newIndex );
pixhawk's avatar
pixhawk committed
291

Bryant's avatar
Bryant committed
292
        d_data->zoomRectIndex = uint( newIndex );
pixhawk's avatar
pixhawk committed
293 294 295 296
    }

    rescale();

Bryant's avatar
Bryant committed
297
    Q_EMIT zoomed( zoomRect() );
pixhawk's avatar
pixhawk committed
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
}

/*!
  \brief Assign a zoom stack

  In combination with other types of navigation it might be useful to
  modify to manipulate the complete zoom stack.

  \param zoomStack New zoom stack
  \param zoomRectIndex Index of the current position of zoom stack.
                       In case of -1 the current position is at the top
                       of the stack.

  \note The zoomed signal might be emitted.
  \sa zoomStack(), zoomRectIndex()
*/
void QwtPlotZoomer::setZoomStack(
Bryant's avatar
Bryant committed
315
    const QStack<QRectF> &zoomStack, int zoomRectIndex )
pixhawk's avatar
pixhawk committed
316 317 318 319 320
{
    if ( zoomStack.isEmpty() )
        return;

    if ( d_data->maxStackDepth >= 0 &&
Bryant's avatar
Bryant committed
321 322
        int( zoomStack.count() ) > d_data->maxStackDepth )
    {
pixhawk's avatar
pixhawk committed
323 324 325
        return;
    }

Bryant's avatar
Bryant committed
326
    if ( zoomRectIndex < 0 || zoomRectIndex > int( zoomStack.count() ) )
pixhawk's avatar
pixhawk committed
327 328 329 330 331
        zoomRectIndex = zoomStack.count() - 1;

    const bool doRescale = zoomStack[zoomRectIndex] != zoomRect();

    d_data->zoomStack = zoomStack;
Bryant's avatar
Bryant committed
332
    d_data->zoomRectIndex = uint( zoomRectIndex );
pixhawk's avatar
pixhawk committed
333

Bryant's avatar
Bryant committed
334 335
    if ( doRescale )
    {
pixhawk's avatar
pixhawk committed
336
        rescale();
Bryant's avatar
Bryant committed
337
        Q_EMIT zoomed( zoomRect() );
pixhawk's avatar
pixhawk committed
338 339 340
    }
}

341
/*!
pixhawk's avatar
pixhawk committed
342 343
  Adjust the observed plot to zoomRect()

Bryant's avatar
Bryant committed
344
  \note Initiates QwtPlot::replot()
pixhawk's avatar
pixhawk committed
345 346 347 348 349 350 351 352
*/

void QwtPlotZoomer::rescale()
{
    QwtPlot *plt = plot();
    if ( !plt )
        return;

Bryant's avatar
Bryant committed
353 354 355
    const QRectF &rect = d_data->zoomStack[d_data->zoomRectIndex];
    if ( rect != scaleRect() )
    {
pixhawk's avatar
pixhawk committed
356
        const bool doReplot = plt->autoReplot();
Bryant's avatar
Bryant committed
357
        plt->setAutoReplot( false );
pixhawk's avatar
pixhawk committed
358 359 360

        double x1 = rect.left();
        double x2 = rect.right();
Bryant's avatar
Bryant committed
361 362
        if ( !plt->axisScaleDiv( xAxis() ).isIncreasing() )
            qSwap( x1, x2 );
pixhawk's avatar
pixhawk committed
363

Bryant's avatar
Bryant committed
364
        plt->setAxisScale( xAxis(), x1, x2 );
pixhawk's avatar
pixhawk committed
365 366 367

        double y1 = rect.top();
        double y2 = rect.bottom();
Bryant's avatar
Bryant committed
368 369
        if ( !plt->axisScaleDiv( yAxis() ).isIncreasing() )
            qSwap( y1, y2 );
pixhawk's avatar
pixhawk committed
370

Bryant's avatar
Bryant committed
371 372 373
        plt->setAxisScale( yAxis(), y1, y2 );

        plt->setAutoReplot( doReplot );
pixhawk's avatar
pixhawk committed
374 375 376 377 378 379 380 381

        plt->replot();
    }
}

/*!
  Reinitialize the axes, and set the zoom base to their scales.

382
  \param xAxis X axis
pixhawk's avatar
pixhawk committed
383 384 385
  \param yAxis Y axis
*/

Bryant's avatar
Bryant committed
386
void QwtPlotZoomer::setAxis( int xAxis, int yAxis )
pixhawk's avatar
pixhawk committed
387
{
Bryant's avatar
Bryant committed
388 389 390 391
    if ( xAxis != QwtPlotPicker::xAxis() || yAxis != QwtPlotPicker::yAxis() )
    {
        QwtPlotPicker::setAxis( xAxis, yAxis );
        setZoomBase( scaleRect() );
pixhawk's avatar
pixhawk committed
392 393 394 395 396 397 398 399 400 401 402 403 404
    }
}

/*!
   Qt::MidButton zooms out one position on the zoom stack,
   Qt::RightButton to the zoom base.

   Changes the current position on the stack, but doesn't pop
   any rectangle.

   \note The mouse events can be changed, using
         QwtEventPattern::setMousePattern: 2, 1
*/
Bryant's avatar
Bryant committed
405
void QwtPlotZoomer::widgetMouseReleaseEvent( QMouseEvent *me )
pixhawk's avatar
pixhawk committed
406
{
Bryant's avatar
Bryant committed
407 408 409 410 411 412
    if ( mouseMatch( MouseSelect2, me ) )
        zoom( 0 );
    else if ( mouseMatch( MouseSelect3, me ) )
        zoom( -1 );
    else if ( mouseMatch( MouseSelect6, me ) )
        zoom( +1 );
413
    else
Bryant's avatar
Bryant committed
414
        QwtPlotPicker::widgetMouseReleaseEvent( me );
pixhawk's avatar
pixhawk committed
415 416 417
}

/*!
Bryant's avatar
Bryant committed
418
   Qt::Key_Plus zooms in, Qt::Key_Minus zooms out one position on the
pixhawk's avatar
pixhawk committed
419 420 421 422 423 424 425 426 427
   zoom stack, Qt::Key_Escape zooms out to the zoom base.

   Changes the current position on the stack, but doesn't pop
   any rectangle.

   \note The keys codes can be changed, using
         QwtEventPattern::setKeyPattern: 3, 4, 5
*/

Bryant's avatar
Bryant committed
428
void QwtPlotZoomer::widgetKeyPressEvent( QKeyEvent *ke )
pixhawk's avatar
pixhawk committed
429
{
Bryant's avatar
Bryant committed
430 431 432 433 434 435 436 437
    if ( !isActive() )
    {
        if ( keyMatch( KeyUndo, ke ) )
            zoom( -1 );
        else if ( keyMatch( KeyRedo, ke ) )
            zoom( +1 );
        else if ( keyMatch( KeyHome, ke ) )
            zoom( 0 );
pixhawk's avatar
pixhawk committed
438 439
    }

Bryant's avatar
Bryant committed
440
    QwtPlotPicker::widgetKeyPressEvent( ke );
pixhawk's avatar
pixhawk committed
441 442 443 444 445 446 447 448 449 450
}

/*!
  Move the current zoom rectangle.

  \param dx X offset
  \param dy Y offset

  \note The changed rectangle is limited by the zoom base
*/
Bryant's avatar
Bryant committed
451
void QwtPlotZoomer::moveBy( double dx, double dy )
pixhawk's avatar
pixhawk committed
452
{
Bryant's avatar
Bryant committed
453 454
    const QRectF &rect = d_data->zoomStack[d_data->zoomRectIndex];
    moveTo( QPointF( rect.left() + dx, rect.top() + dy ) );
pixhawk's avatar
pixhawk committed
455 456 457 458 459
}

/*!
  Move the the current zoom rectangle.

Bryant's avatar
Bryant committed
460
  \param pos New position
pixhawk's avatar
pixhawk committed
461

Bryant's avatar
Bryant committed
462
  \sa QRectF::moveTo()
pixhawk's avatar
pixhawk committed
463 464
  \note The changed rectangle is limited by the zoom base
*/
Bryant's avatar
Bryant committed
465
void QwtPlotZoomer::moveTo( const QPointF &pos )
pixhawk's avatar
pixhawk committed
466
{
Bryant's avatar
Bryant committed
467 468 469
    double x = pos.x();
    double y = pos.y();

pixhawk's avatar
pixhawk committed
470 471 472 473 474 475 476 477 478 479
    if ( x < zoomBase().left() )
        x = zoomBase().left();
    if ( x > zoomBase().right() - zoomRect().width() )
        x = zoomBase().right() - zoomRect().width();

    if ( y < zoomBase().top() )
        y = zoomBase().top();
    if ( y > zoomBase().bottom() - zoomRect().height() )
        y = zoomBase().bottom() - zoomRect().height();

Bryant's avatar
Bryant committed
480 481 482
    if ( x != zoomRect().left() || y != zoomRect().top() )
    {
        d_data->zoomStack[d_data->zoomRectIndex].moveTo( x, y );
pixhawk's avatar
pixhawk committed
483 484 485 486 487 488 489
        rescale();
    }
}

/*!
  \brief Check and correct a selected rectangle

Bryant's avatar
Bryant committed
490
  Reject rectangles with a height or width < 2, otherwise
pixhawk's avatar
pixhawk committed
491 492
  expand the selected rectangle to a minimum size of 11x11
  and accept it.
493

Bryant's avatar
Bryant committed
494 495
  \return true If the rectangle is accepted, or has been changed
          to an accepted one.
pixhawk's avatar
pixhawk committed
496 497
*/

Bryant's avatar
Bryant committed
498
bool QwtPlotZoomer::accept( QPolygon &pa ) const
pixhawk's avatar
pixhawk committed
499 500 501 502
{
    if ( pa.count() < 2 )
        return false;

Bryant's avatar
Bryant committed
503
    QRect rect = QRect( pa[0], pa[int( pa.count() ) - 1] );
pixhawk's avatar
pixhawk committed
504 505 506
    rect = rect.normalized();

    const int minSize = 2;
Bryant's avatar
Bryant committed
507
    if ( rect.width() < minSize && rect.height() < minSize )
508
        return false;
pixhawk's avatar
pixhawk committed
509 510 511 512

    const int minZoomSize = 11;

    const QPoint center = rect.center();
Bryant's avatar
Bryant committed
513 514
    rect.setSize( rect.size().expandedTo( QSize( minZoomSize, minZoomSize ) ) );
    rect.moveCenter( center );
pixhawk's avatar
pixhawk committed
515

Bryant's avatar
Bryant committed
516
    pa.resize( 2 );
pixhawk's avatar
pixhawk committed
517 518 519 520 521 522 523 524 525 526 527
    pa[0] = rect.topLeft();
    pa[1] = rect.bottomRight();

    return true;
}

/*!
  \brief Limit zooming by a minimum rectangle

  \return zoomBase().width() / 10e4, zoomBase().height() / 10e4
*/
Bryant's avatar
Bryant committed
528
QSizeF QwtPlotZoomer::minZoomSize() const
pixhawk's avatar
pixhawk committed
529
{
Bryant's avatar
Bryant committed
530 531
    return QSizeF( d_data->zoomStack[0].width() / 10e4,
        d_data->zoomStack[0].height() / 10e4 );
pixhawk's avatar
pixhawk committed
532 533
}

534
/*!
pixhawk's avatar
pixhawk committed
535 536 537 538 539 540 541
  Rejects selections, when the stack depth is too deep, or
  the zoomed rectangle is minZoomSize().

  \sa minZoomSize(), maxStackDepth()
*/
void QwtPlotZoomer::begin()
{
Bryant's avatar
Bryant committed
542 543 544
    if ( d_data->maxStackDepth >= 0 )
    {
        if ( d_data->zoomRectIndex >= uint( d_data->maxStackDepth ) )
pixhawk's avatar
pixhawk committed
545 546 547
            return;
    }

Bryant's avatar
Bryant committed
548 549 550 551
    const QSizeF minSize = minZoomSize();
    if ( minSize.isValid() )
    {
        const QSizeF sz =
pixhawk's avatar
pixhawk committed
552 553 554
            d_data->zoomStack[d_data->zoomRectIndex].size() * 0.9999;

        if ( minSize.width() >= sz.width() &&
Bryant's avatar
Bryant committed
555 556
            minSize.height() >= sz.height() )
        {
pixhawk's avatar
pixhawk committed
557 558 559 560 561 562 563 564 565 566 567
            return;
        }
    }

    QwtPlotPicker::begin();
}

/*!
  Expand the selected rectangle to minZoomSize() and zoom in
  if accepted.

Bryant's avatar
Bryant committed
568 569 570 571 572
  \param ok If true, complete the selection and emit selected signals
            otherwise discard the selection.

  \sa accept(), minZoomSize()
  \return True if the selection has been accepted, false otherwise
pixhawk's avatar
pixhawk committed
573
*/
Bryant's avatar
Bryant committed
574
bool QwtPlotZoomer::end( bool ok )
pixhawk's avatar
pixhawk committed
575
{
Bryant's avatar
Bryant committed
576 577
    ok = QwtPlotPicker::end( ok );
    if ( !ok )
pixhawk's avatar
pixhawk committed
578 579 580 581 582 583
        return false;

    QwtPlot *plot = QwtPlotZoomer::plot();
    if ( !plot )
        return false;

Bryant's avatar
Bryant committed
584
    const QPolygon &pa = selection();
pixhawk's avatar
pixhawk committed
585 586 587
    if ( pa.count() < 2 )
        return false;

Bryant's avatar
Bryant committed
588
    QRect rect = QRect( pa[0], pa[int( pa.count() - 1 )] );
pixhawk's avatar
pixhawk committed
589 590
    rect = rect.normalized();

Bryant's avatar
Bryant committed
591
    QRectF zoomRect = invTransform( rect ).normalized();
pixhawk's avatar
pixhawk committed
592

Bryant's avatar
Bryant committed
593 594 595 596 597 598 599
    const QSizeF minSize = minZoomSize();
    if ( minSize.isValid() )
    {
        const QPointF center = zoomRect.center();
        zoomRect.setSize( zoomRect.size().expandedTo( minZoomSize() ) );
        zoomRect.moveCenter( center );
    }
pixhawk's avatar
pixhawk committed
600

Bryant's avatar
Bryant committed
601
    zoom( zoomRect );
pixhawk's avatar
pixhawk committed
602 603 604

    return true;
}