qwt_counter.cpp 17.5 KB
Newer Older
pixhawk's avatar
pixhawk committed
1 2 3 4 5 6 7 8 9
/* -*- 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
 *****************************************************************************/

Bryant's avatar
Bryant committed
10 11 12
#include "qwt_arrow_button.h"
#include "qwt_math.h"
#include "qwt_counter.h"
pixhawk's avatar
pixhawk committed
13 14 15 16 17 18 19 20 21 22
#include <qlayout.h>
#include <qlineedit.h>
#include <qvalidator.h>
#include <qevent.h>
#include <qstyle.h>

class QwtCounter::PrivateData
{
public:
    PrivateData():
Bryant's avatar
Bryant committed
23 24 25 26 27 28 29
        minimum( 0.0 ),
        maximum( 0.0 ),
        singleStep( 1.0 ),
        isValid( false ),
        value( 0.0 ),
        wrapping( false )
    {
pixhawk's avatar
pixhawk committed
30 31 32 33 34 35 36 37 38 39
        increment[Button1] = 1;
        increment[Button2] = 10;
        increment[Button3] = 100;
    }

    QwtArrowButton *buttonDown[ButtonCnt];
    QwtArrowButton *buttonUp[ButtonCnt];
    QLineEdit *valueEdit;

    int increment[ButtonCnt];
Bryant's avatar
Bryant committed
40
    int numButtons;
pixhawk's avatar
pixhawk committed
41

Bryant's avatar
Bryant committed
42 43 44
    double minimum;
    double maximum;
    double singleStep;
pixhawk's avatar
pixhawk committed
45

Bryant's avatar
Bryant committed
46 47
    bool isValid;
    double value;
pixhawk's avatar
pixhawk committed
48

Bryant's avatar
Bryant committed
49 50
    bool wrapping;
};
pixhawk's avatar
pixhawk committed
51 52

/*!
Bryant's avatar
Bryant committed
53 54 55
  The counter is initialized with a range is set to [0.0, 1.0] with 
  0.01 as single step size. The value is invalid.

pixhawk's avatar
pixhawk committed
56 57 58 59 60 61 62
  The default number of buttons is set to 2. The default increments are:
  \li Button 1: 1 step
  \li Button 2: 10 steps
  \li Button 3: 100 steps

  \param parent
 */
Bryant's avatar
Bryant committed
63 64
QwtCounter::QwtCounter( QWidget *parent ):
    QWidget( parent )
pixhawk's avatar
pixhawk committed
65 66 67 68 69 70 71 72
{
    initCounter();
}

void QwtCounter::initCounter()
{
    d_data = new PrivateData;

Bryant's avatar
Bryant committed
73 74 75
    QHBoxLayout *layout = new QHBoxLayout( this );
    layout->setSpacing( 0 );
    layout->setMargin( 0 );
pixhawk's avatar
pixhawk committed
76

Bryant's avatar
Bryant committed
77 78
    for ( int i = ButtonCnt - 1; i >= 0; i-- )
    {
pixhawk's avatar
pixhawk committed
79
        QwtArrowButton *btn =
Bryant's avatar
Bryant committed
80 81 82 83
            new QwtArrowButton( i + 1, Qt::DownArrow, this );
        btn->setFocusPolicy( Qt::NoFocus );
        btn->installEventFilter( this );
        layout->addWidget( btn );
pixhawk's avatar
pixhawk committed
84

Bryant's avatar
Bryant committed
85 86
        connect( btn, SIGNAL( released() ), SLOT( btnReleased() ) );
        connect( btn, SIGNAL( clicked() ), SLOT( btnClicked() ) );
pixhawk's avatar
pixhawk committed
87 88 89 90

        d_data->buttonDown[i] = btn;
    }

Bryant's avatar
Bryant committed
91 92 93 94
    d_data->valueEdit = new QLineEdit( this );
    d_data->valueEdit->setReadOnly( false );
    d_data->valueEdit->setValidator( new QDoubleValidator( d_data->valueEdit ) );
    layout->addWidget( d_data->valueEdit );
pixhawk's avatar
pixhawk committed
95

Bryant's avatar
Bryant committed
96 97
    connect( d_data->valueEdit, SIGNAL( editingFinished() ),
         SLOT( textChanged() ) );
pixhawk's avatar
pixhawk committed
98

Bryant's avatar
Bryant committed
99 100 101 102
    layout->setStretchFactor( d_data->valueEdit, 10 );

    for ( int i = 0; i < ButtonCnt; i++ )
    {
pixhawk's avatar
pixhawk committed
103
        QwtArrowButton *btn =
Bryant's avatar
Bryant committed
104 105 106 107
            new QwtArrowButton( i + 1, Qt::UpArrow, this );
        btn->setFocusPolicy( Qt::NoFocus );
        btn->installEventFilter( this );
        layout->addWidget( btn );
pixhawk's avatar
pixhawk committed
108

Bryant's avatar
Bryant committed
109 110
        connect( btn, SIGNAL( released() ), SLOT( btnReleased() ) );
        connect( btn, SIGNAL( clicked() ), SLOT( btnClicked() ) );
111

pixhawk's avatar
pixhawk committed
112 113 114
        d_data->buttonUp[i] = btn;
    }

Bryant's avatar
Bryant committed
115 116 117 118
    setNumButtons( 2 );
    setRange( 0.0, 1.0 );
    setSingleStep( 0.001 );
    setValue( 0.0 );
pixhawk's avatar
pixhawk committed
119 120

    setSizePolicy(
Bryant's avatar
Bryant committed
121
        QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) );
pixhawk's avatar
pixhawk committed
122

Bryant's avatar
Bryant committed
123 124
    setFocusProxy( d_data->valueEdit );
    setFocusPolicy( Qt::StrongFocus );
pixhawk's avatar
pixhawk committed
125 126 127 128 129 130 131 132
}

//! Destructor
QwtCounter::~QwtCounter()
{
    delete d_data;
}

Bryant's avatar
Bryant committed
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
/*! 
  Set the counter to be in valid/invalid state

  When the counter is set to invalid, no numbers are displayed and
  the buttons are disabled.

  \param on If true the counter will be set as valid 

  \sa setValue(), isValid()
*/
void QwtCounter::setValid( bool on )
{
    if ( on != d_data->isValid )
    {
        d_data->isValid = on;

        updateButtons();

        if ( d_data->isValid )
        {
            showNumber( value() );
            Q_EMIT valueChanged( value() );
        }
        else
        {
            d_data->valueEdit->setText( QString::null );
        }
    }   
}   

/*! 
  \return True, if the value is valid
  \sa setValid(), setValue()
 */
bool QwtCounter::isValid() const
{
    return d_data->isValid;
}   

/*!
  \brief Allow/disallow the user to manually edit the value

  \param on True disable editing
  \sa isReadOnly()
*/
void QwtCounter::setReadOnly( bool on )
{
    d_data->valueEdit->setReadOnly( on );
}

/*! 
   \return True, when the line line edit is read only. (default is no)
  \sa setReadOnly()
 */
bool QwtCounter::isReadOnly() const
{
    return d_data->valueEdit->isReadOnly();
}

pixhawk's avatar
pixhawk committed
192
/*!
Bryant's avatar
Bryant committed
193 194 195 196 197 198 199 200
  \brief Set a new value without adjusting to the step raster

  The state of the counter is set to be valid.

  \param value New value

  \sa isValid(), value(), valueChanged()
  \warning The value is clipped when it lies outside the range.
pixhawk's avatar
pixhawk committed
201
*/
Bryant's avatar
Bryant committed
202 203

void QwtCounter::setValue( double value )
pixhawk's avatar
pixhawk committed
204
{
Bryant's avatar
Bryant committed
205 206 207 208 209 210 211 212 213 214 215 216
    const double vmin = qMin( d_data->minimum, d_data->maximum );
    const double vmax = qMax( d_data->minimum, d_data->maximum );

    value = qBound( vmin, value, vmax );

    if ( !d_data->isValid || value != d_data->value )
    {
        d_data->isValid = true;
        d_data->value = value;

        showNumber( value );
        updateButtons();
pixhawk's avatar
pixhawk committed
217

Bryant's avatar
Bryant committed
218
        Q_EMIT valueChanged( value );
pixhawk's avatar
pixhawk committed
219
    }
Bryant's avatar
Bryant committed
220
}
pixhawk's avatar
pixhawk committed
221

Bryant's avatar
Bryant committed
222 223 224 225 226 227 228
/*!
  \return Current value of the counter
  \sa setValue(), valueChanged()
 */
double QwtCounter::value() const
{
    return d_data->value;
pixhawk's avatar
pixhawk committed
229 230
}

Bryant's avatar
Bryant committed
231 232 233 234 235 236 237 238 239 240 241 242
/*!
  \brief Set the minimum and maximum values

  The maximum is adjusted if necessary to ensure that the range remains valid.
  The value might be modified to be inside of the range.

  \param min Minimum value
  \param max Maximum value

  \sa minimum(), maximum()
 */
void QwtCounter::setRange( double min, double max )
pixhawk's avatar
pixhawk committed
243
{
Bryant's avatar
Bryant committed
244 245 246
    max = qMax( min, max );

    if ( d_data->maximum == max && d_data->minimum == min )
pixhawk's avatar
pixhawk committed
247 248
        return;

Bryant's avatar
Bryant committed
249 250
    d_data->minimum = min;
    d_data->maximum = max;
pixhawk's avatar
pixhawk committed
251

Bryant's avatar
Bryant committed
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
    setSingleStep( singleStep() );

    const double value = qBound( min, d_data->value, max );

    if ( value != d_data->value )
    {
        d_data->value = value;

        if ( d_data->isValid )
        {
            showNumber( value );
            Q_EMIT valueChanged( value );
        }
    }

    updateButtons();
pixhawk's avatar
pixhawk committed
268 269
}

Bryant's avatar
Bryant committed
270 271
/*!
  Set the minimum value of the range
pixhawk's avatar
pixhawk committed
272

Bryant's avatar
Bryant committed
273 274 275 276
  \param value Minimum value
  \sa setRange(), setMaximum(), minimum()

  \note The maximum is adjusted if necessary to ensure that the range remains valid.
pixhawk's avatar
pixhawk committed
277
*/
Bryant's avatar
Bryant committed
278
void QwtCounter::setMinimum( double value )
pixhawk's avatar
pixhawk committed
279
{
Bryant's avatar
Bryant committed
280 281
    setRange( value, maximum() );
}
pixhawk's avatar
pixhawk committed
282

Bryant's avatar
Bryant committed
283 284 285 286 287 288 289
/*!
  \return The minimum of the range
  \sa setRange(), setMinimum(), maximum()
*/
double QwtCounter::minimum() const
{
    return d_data->minimum;
pixhawk's avatar
pixhawk committed
290 291
}

Bryant's avatar
Bryant committed
292 293 294 295 296 297 298
/*!
  Set the maximum value of the range

  \param value Maximum value
  \sa setRange(), setMinimum(), maximum()
*/
void QwtCounter::setMaximum( double value )
299
{
Bryant's avatar
Bryant committed
300
    setRange( minimum(), value );
pixhawk's avatar
pixhawk committed
301 302 303
}

/*!
Bryant's avatar
Bryant committed
304 305
  \return The maximum of the range
  \sa setRange(), setMaximum(), minimum()
pixhawk's avatar
pixhawk committed
306
*/
Bryant's avatar
Bryant committed
307
double QwtCounter::maximum() const
pixhawk's avatar
pixhawk committed
308
{
Bryant's avatar
Bryant committed
309
    return d_data->maximum;
pixhawk's avatar
pixhawk committed
310 311 312
}

/*!
Bryant's avatar
Bryant committed
313
  \brief Set the step size of the counter
pixhawk's avatar
pixhawk committed
314

Bryant's avatar
Bryant committed
315 316 317 318
  A value <= 0.0 disables stepping

  \param stepSize Single step size
  \sa singleStep()
pixhawk's avatar
pixhawk committed
319
*/
Bryant's avatar
Bryant committed
320 321 322 323
void QwtCounter::setSingleStep( double stepSize )
{
    d_data->singleStep = qMax( stepSize, 0.0 );
}
pixhawk's avatar
pixhawk committed
324

Bryant's avatar
Bryant committed
325 326 327 328 329
/*!
  \return Single step size
  \sa setSingleStep()
 */
double QwtCounter::singleStep() const
pixhawk's avatar
pixhawk committed
330
{
Bryant's avatar
Bryant committed
331 332
    return d_data->singleStep;
}
pixhawk's avatar
pixhawk committed
333

Bryant's avatar
Bryant committed
334 335
/*!
  \brief En/Disable wrapping
pixhawk's avatar
pixhawk committed
336

Bryant's avatar
Bryant committed
337 338
  If wrapping is true stepping up from maximum() value will take 
  you to the minimum() value and vice versa. 
pixhawk's avatar
pixhawk committed
339

Bryant's avatar
Bryant committed
340 341 342 343 344 345
  \param on En/Disable wrapping
  \sa wrapping()
 */
void QwtCounter::setWrapping( bool on )
{
    d_data->wrapping = on;
pixhawk's avatar
pixhawk committed
346 347
}

Bryant's avatar
Bryant committed
348 349 350 351 352
/*!
  \return True, when wrapping is set
  \sa setWrapping()
 */
bool QwtCounter::wrapping() const
pixhawk's avatar
pixhawk committed
353
{
Bryant's avatar
Bryant committed
354 355
    return d_data->wrapping;
}
pixhawk's avatar
pixhawk committed
356

Bryant's avatar
Bryant committed
357 358
/*!
  Specify the number of buttons on each side of the label
pixhawk's avatar
pixhawk committed
359

Bryant's avatar
Bryant committed
360 361 362 363 364 365 366
  \param numButtons Number of buttons
  \sa numButtons()
*/
void QwtCounter::setNumButtons( int numButtons )
{
    if ( numButtons < 0 || numButtons > QwtCounter::ButtonCnt )
        return;
367

Bryant's avatar
Bryant committed
368 369 370 371 372 373 374 375 376 377 378
    for ( int i = 0; i < QwtCounter::ButtonCnt; i++ )
    {
        if ( i < numButtons )
        {
            d_data->buttonDown[i]->show();
            d_data->buttonUp[i]->show();
        }
        else
        {
            d_data->buttonDown[i]->hide();
            d_data->buttonUp[i]->hide();
pixhawk's avatar
pixhawk committed
379 380 381
        }
    }

Bryant's avatar
Bryant committed
382 383
    d_data->numButtons = numButtons;
}
pixhawk's avatar
pixhawk committed
384

Bryant's avatar
Bryant committed
385 386 387 388 389 390 391
/*!
  \return The number of buttons on each side of the widget.
  \sa setNumButtons()
*/
int QwtCounter::numButtons() const
{
    return d_data->numButtons;
pixhawk's avatar
pixhawk committed
392 393 394 395 396 397 398
}

/*!
  Specify the number of steps by which the value
  is incremented or decremented when a specified button
  is pushed.

Bryant's avatar
Bryant committed
399 400 401 402
  \param button Button index
  \param numSteps Number of steps

  \sa incSteps()
pixhawk's avatar
pixhawk committed
403
*/
Bryant's avatar
Bryant committed
404
void QwtCounter::setIncSteps( QwtCounter::Button button, int numSteps )
pixhawk's avatar
pixhawk committed
405
{
Bryant's avatar
Bryant committed
406 407
    if ( button >= 0 && button < QwtCounter::ButtonCnt )
        d_data->increment[ button ] = numSteps;
pixhawk's avatar
pixhawk committed
408 409 410
}

/*!
Bryant's avatar
Bryant committed
411 412 413 414 415
  \return The number of steps by which a specified button increments the value
          or 0 if the button is invalid.
  \param button Button index

  \sa setIncSteps()
pixhawk's avatar
pixhawk committed
416
*/
Bryant's avatar
Bryant committed
417
int QwtCounter::incSteps( QwtCounter::Button button ) const
pixhawk's avatar
pixhawk committed
418
{
Bryant's avatar
Bryant committed
419 420
    if ( button >= 0 && button < QwtCounter::ButtonCnt )
        return d_data->increment[ button ];
pixhawk's avatar
pixhawk committed
421 422 423 424

    return 0;
}

Bryant's avatar
Bryant committed
425

pixhawk's avatar
pixhawk committed
426
/*!
Bryant's avatar
Bryant committed
427 428
  Set the number of increment steps for button 1
  \param nSteps Number of steps
pixhawk's avatar
pixhawk committed
429
*/
Bryant's avatar
Bryant committed
430 431 432 433
void QwtCounter::setStepButton1( int nSteps )
{
    setIncSteps( QwtCounter::Button1, nSteps );
}
pixhawk's avatar
pixhawk committed
434

Bryant's avatar
Bryant committed
435 436
//! returns the number of increment steps for button 1
int QwtCounter::stepButton1() const
pixhawk's avatar
pixhawk committed
437
{
Bryant's avatar
Bryant committed
438 439
    return incSteps( QwtCounter::Button1 );
}
pixhawk's avatar
pixhawk committed
440

Bryant's avatar
Bryant committed
441 442 443 444 445 446 447 448 449 450 451 452 453
/*!
  Set the number of increment steps for button 2
  \param nSteps Number of steps
*/
void QwtCounter::setStepButton2( int nSteps )
{
    setIncSteps( QwtCounter::Button2, nSteps );
}

//! returns the number of increment steps for button 2
int QwtCounter::stepButton2() const
{
    return incSteps( QwtCounter::Button2 );
pixhawk's avatar
pixhawk committed
454 455 456
}

/*!
Bryant's avatar
Bryant committed
457 458
  Set the number of increment steps for button 3
  \param nSteps Number of steps
pixhawk's avatar
pixhawk committed
459
*/
Bryant's avatar
Bryant committed
460
void QwtCounter::setStepButton3( int nSteps )
pixhawk's avatar
pixhawk committed
461
{
Bryant's avatar
Bryant committed
462 463
    setIncSteps( QwtCounter::Button3, nSteps );
}
pixhawk's avatar
pixhawk committed
464

Bryant's avatar
Bryant committed
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
//! returns the number of increment steps for button 3
int QwtCounter::stepButton3() const
{
    return incSteps( QwtCounter::Button3 );
}

//! Set from lineedit
void QwtCounter::textChanged()
{
    bool converted = false;

    const double value = d_data->valueEdit->text().toDouble( &converted );
    if ( converted )
        setValue( value );
}
pixhawk's avatar
pixhawk committed
480

Bryant's avatar
Bryant committed
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498
/*!
   Handle QEvent::PolishRequest events
   \param event Event
   \return see QWidget::event()
*/
bool QwtCounter::event( QEvent *event )
{
    if ( event->type() == QEvent::PolishRequest )
    {
        const int w = d_data->valueEdit->fontMetrics().width( "W" ) + 8;
        for ( int i = 0; i < ButtonCnt; i++ )
        {
            d_data->buttonDown[i]->setMinimumWidth( w );
            d_data->buttonUp[i]->setMinimumWidth( w );
        }
    }

    return QWidget::event( event );
pixhawk's avatar
pixhawk committed
499 500 501
}

/*!
Bryant's avatar
Bryant committed
502
  Handle key events
pixhawk's avatar
pixhawk committed
503

Bryant's avatar
Bryant committed
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519
  - Ctrl + Qt::Key_Home\n
    Step to minimum()
  - Ctrl + Qt::Key_End\n
    Step to maximum()
  - Qt::Key_Up\n
    Increment by incSteps(QwtCounter::Button1)
  - Qt::Key_Down\n
    Decrement by incSteps(QwtCounter::Button1)
  - Qt::Key_PageUp\n
    Increment by incSteps(QwtCounter::Button2)
  - Qt::Key_PageDown\n
    Decrement by incSteps(QwtCounter::Button2)
  - Shift + Qt::Key_PageUp\n
    Increment by incSteps(QwtCounter::Button3)
  - Shift + Qt::Key_PageDown\n
    Decrement by incSteps(QwtCounter::Button3)
pixhawk's avatar
pixhawk committed
520

Bryant's avatar
Bryant committed
521
  \param event Key event
pixhawk's avatar
pixhawk committed
522
*/
Bryant's avatar
Bryant committed
523
void QwtCounter::keyPressEvent ( QKeyEvent *event )
pixhawk's avatar
pixhawk committed
524
{
Bryant's avatar
Bryant committed
525
    bool accepted = true;
pixhawk's avatar
pixhawk committed
526

Bryant's avatar
Bryant committed
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
    switch ( event->key() )
    {
        case Qt::Key_Home:
        {
            if ( event->modifiers() & Qt::ControlModifier )
                setValue( minimum() );
            else
                accepted = false;
            break;
        }
        case Qt::Key_End:
        {
            if ( event->modifiers() & Qt::ControlModifier )
                setValue( maximum() );
            else
                accepted = false;
            break;
        }
        case Qt::Key_Up:
        {
            incrementValue( d_data->increment[0] );
            break;
pixhawk's avatar
pixhawk committed
549
        }
Bryant's avatar
Bryant committed
550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573
        case Qt::Key_Down:
        {
            incrementValue( -d_data->increment[0] );
            break;
        }
        case Qt::Key_PageUp:
        case Qt::Key_PageDown:
        {
            int increment = d_data->increment[0];
            if ( d_data->numButtons >= 2 )
                increment = d_data->increment[1];
            if ( d_data->numButtons >= 3 )
            {
                if ( event->modifiers() & Qt::ShiftModifier )
                    increment = d_data->increment[2];
            }
            if ( event->key() == Qt::Key_PageDown )
                increment = -increment;
            incrementValue( increment );
            break;
        }
        default:
        {
            accepted = false;
pixhawk's avatar
pixhawk committed
574 575
        }
    }
Bryant's avatar
Bryant committed
576 577 578 579 580 581 582 583

    if ( accepted )
    {
        event->accept();
        return;
    }

    QWidget::keyPressEvent ( event );
pixhawk's avatar
pixhawk committed
584 585 586
}

/*!
Bryant's avatar
Bryant committed
587 588
  Handle wheel events
  \param event Wheel event
pixhawk's avatar
pixhawk committed
589
*/
Bryant's avatar
Bryant committed
590
void QwtCounter::wheelEvent( QWheelEvent *event )
pixhawk's avatar
pixhawk committed
591
{
Bryant's avatar
Bryant committed
592 593 594
    event->accept();

    if ( d_data->numButtons <= 0 )
pixhawk's avatar
pixhawk committed
595 596
        return;

Bryant's avatar
Bryant committed
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651
    int increment = d_data->increment[0];
    if ( d_data->numButtons >= 2 )
    {
        if ( event->modifiers() & Qt::ControlModifier )
            increment = d_data->increment[1];
    }
    if ( d_data->numButtons >= 3 )
    {
        if ( event->modifiers() & Qt::ShiftModifier )
            increment = d_data->increment[2];
    }

    for ( int i = 0; i < d_data->numButtons; i++ )
    {
        if ( d_data->buttonDown[i]->geometry().contains( event->pos() ) ||
            d_data->buttonUp[i]->geometry().contains( event->pos() ) )
        {
            increment = d_data->increment[i];
        }
    }

    const int wheel_delta = 120;

#if 1
    int delta = event->delta();
    if ( delta >= 2 * wheel_delta )
        delta /= 2; // Never saw an abs(delta) < 240
#endif

    incrementValue( delta / wheel_delta * increment );
}

void QwtCounter::incrementValue( int numSteps )
{
    const double min = d_data->minimum;
    const double max = d_data->maximum;
    double stepSize = d_data->singleStep;

    if ( !d_data->isValid || min >= max || stepSize <= 0.0 )
        return;


#if 1
    stepSize = qMax( stepSize, 1.0e-10 * ( max - min ) );
#endif

    double value = d_data->value + numSteps * stepSize;

    if ( d_data->wrapping )
    {
        const double range = max - min;

        if ( value < min )
        {
            value += ::ceil( ( min - value ) / range ) * range;
pixhawk's avatar
pixhawk committed
652
        }
Bryant's avatar
Bryant committed
653 654 655 656 657 658 659 660
        else if ( value > max )
        {
            value -= ::ceil( ( value - max ) / range ) * range;
        }
    }
    else
    {
        value = qBound( min, value, max );
pixhawk's avatar
pixhawk committed
661 662
    }

Bryant's avatar
Bryant committed
663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686
    value = min + qRound( ( value - min ) / stepSize ) * stepSize;

    if ( stepSize > 1e-12 )
    {
        if ( qFuzzyCompare( value + 1.0, 1.0 ) )
        {
            // correct rounding error if value = 0
            value = 0.0;
        }
        else if ( qFuzzyCompare( value, max ) )
        {
            // correct rounding error at the border
            value = max;
        }
    }

    if ( value != d_data->value )
    {
        d_data->value = value;
        showNumber( d_data->value );
        updateButtons();

        Q_EMIT valueChanged( d_data->value );
    }
pixhawk's avatar
pixhawk committed
687 688
}

Bryant's avatar
Bryant committed
689

pixhawk's avatar
pixhawk committed
690
/*!
Bryant's avatar
Bryant committed
691 692 693 694 695 696
  \brief Update buttons according to the current value

  When the QwtCounter under- or over-flows, the focus is set to the smallest
  up- or down-button and counting is disabled.

  Counting is re-enabled on a button release event (mouse or space bar).
pixhawk's avatar
pixhawk committed
697
*/
Bryant's avatar
Bryant committed
698
void QwtCounter::updateButtons()
699
{
Bryant's avatar
Bryant committed
700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
    if ( d_data->isValid )
    {
        // 1. save enabled state of the smallest down- and up-button
        // 2. change enabled state on under- or over-flow

        for ( int i = 0; i < QwtCounter::ButtonCnt; i++ )
        {
            d_data->buttonDown[i]->setEnabled( value() > minimum() );
            d_data->buttonUp[i]->setEnabled( value() < maximum() );
        }
    }
    else
    {
        for ( int i = 0; i < QwtCounter::ButtonCnt; i++ )
        {
            d_data->buttonDown[i]->setEnabled( false );
            d_data->buttonUp[i]->setEnabled( false );
        }
    }
pixhawk's avatar
pixhawk committed
719
}
Bryant's avatar
Bryant committed
720 721
/*!
  Display number string
pixhawk's avatar
pixhawk committed
722

Bryant's avatar
Bryant committed
723 724 725
  \param number Number
*/
void QwtCounter::showNumber( double number )
pixhawk's avatar
pixhawk committed
726
{
Bryant's avatar
Bryant committed
727 728
    QString text;
    text.setNum( number );
pixhawk's avatar
pixhawk committed
729 730

    const int cursorPos = d_data->valueEdit->cursorPosition();
Bryant's avatar
Bryant committed
731 732
    d_data->valueEdit->setText( text );
    d_data->valueEdit->setCursorPosition( cursorPos );
pixhawk's avatar
pixhawk committed
733 734 735 736 737
}

//!  Button clicked
void QwtCounter::btnClicked()
{
Bryant's avatar
Bryant committed
738 739
    for ( int i = 0; i < ButtonCnt; i++ )
    {
pixhawk's avatar
pixhawk committed
740
        if ( d_data->buttonUp[i] == sender() )
Bryant's avatar
Bryant committed
741
            incrementValue( d_data->increment[i] );
pixhawk's avatar
pixhawk committed
742 743

        if ( d_data->buttonDown[i] == sender() )
Bryant's avatar
Bryant committed
744
            incrementValue( -d_data->increment[i] );
pixhawk's avatar
pixhawk committed
745 746 747 748 749 750
    }
}

//!  Button released
void QwtCounter::btnReleased()
{
Bryant's avatar
Bryant committed
751
    Q_EMIT buttonReleased( value() );
pixhawk's avatar
pixhawk committed
752 753 754 755 756 757 758
}

//! A size hint
QSize QwtCounter::sizeHint() const
{
    QString tmp;

Bryant's avatar
Bryant committed
759 760
    int w = tmp.setNum( minimum() ).length();
    int w1 = tmp.setNum( maximum() ).length();
pixhawk's avatar
pixhawk committed
761 762
    if ( w1 > w )
        w = w1;
Bryant's avatar
Bryant committed
763
    w1 = tmp.setNum( minimum() + singleStep() ).length();
pixhawk's avatar
pixhawk committed
764 765
    if ( w1 > w )
        w = w1;
Bryant's avatar
Bryant committed
766
    w1 = tmp.setNum( maximum() - singleStep() ).length();
pixhawk's avatar
pixhawk committed
767 768 769
    if ( w1 > w )
        w = w1;

Bryant's avatar
Bryant committed
770
    tmp.fill( '9', w );
pixhawk's avatar
pixhawk committed
771

Bryant's avatar
Bryant committed
772 773
    QFontMetrics fm( d_data->valueEdit->font() );
    w = fm.width( tmp ) + 2;
pixhawk's avatar
pixhawk committed
774
    if ( d_data->valueEdit->hasFrame() )
Bryant's avatar
Bryant committed
775
        w += 2 * style()->pixelMetric( QStyle::PM_DefaultFrameWidth );
pixhawk's avatar
pixhawk committed
776 777 778 779 780 781

    // Now we replace default sizeHint contribution of d_data->valueEdit by
    // what we really need.

    w += QWidget::sizeHint().width() - d_data->valueEdit->sizeHint().width();

Bryant's avatar
Bryant committed
782 783 784
    const int h = qMin( QWidget::sizeHint().height(),
        d_data->valueEdit->minimumSizeHint().height() );
    return QSize( w, h );
pixhawk's avatar
pixhawk committed
785
}