Qwt User's Guide 6.3.0
Loading...
Searching...
No Matches
qwt_counter.cpp
1/******************************************************************************
2 * Qwt Widget Library
3 * Copyright (C) 1997 Josef Wilgen
4 * Copyright (C) 2002 Uwe Rathmann
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the Qwt License, Version 1.0
8 *****************************************************************************/
9
10#include "qwt_arrow_button.h"
11#include "qwt_counter.h"
12#include "qwt_painter.h"
13#include "qwt_math.h"
14
15#include <qlayout.h>
16#include <qlineedit.h>
17#include <qvalidator.h>
18#include <qevent.h>
19#include <qstyle.h>
20
21class QwtCounter::PrivateData
22{
23 public:
24 PrivateData()
25 : minimum( 0.0 )
26 , maximum( 0.0 )
27 , singleStep( 1.0 )
28 , isValid( false )
29 , value( 0.0 )
30 , wrapping( false )
31 {
32 increment[Button1] = 1;
33 increment[Button2] = 10;
34 increment[Button3] = 100;
35 }
36
37 QwtArrowButton* buttonDown[ButtonCnt];
38 QwtArrowButton* buttonUp[ButtonCnt];
39 QLineEdit* valueEdit;
40
41 int increment[ButtonCnt];
42 int numButtons;
43
44 double minimum;
45 double maximum;
46 double singleStep;
47
48 bool isValid;
49 double value;
50
51 bool wrapping;
52};
53
65QwtCounter::QwtCounter( QWidget* parent )
66 : QWidget( parent )
67{
68 initCounter();
69}
70
71void QwtCounter::initCounter()
72{
73 m_data = new PrivateData;
74
75 QHBoxLayout* layout = new QHBoxLayout( this );
76 layout->setSpacing( 0 );
77 layout->setContentsMargins( QMargins() );
78
79 for ( int i = ButtonCnt - 1; i >= 0; i-- )
80 {
81 QwtArrowButton* btn =
82 new QwtArrowButton( i + 1, Qt::DownArrow, this );
83 btn->setFocusPolicy( Qt::NoFocus );
84 layout->addWidget( btn );
85
86 connect( btn, SIGNAL(released()), SLOT(btnReleased()) );
87 connect( btn, SIGNAL(clicked()), SLOT(btnClicked()) );
88
89 m_data->buttonDown[i] = btn;
90 }
91
92 m_data->valueEdit = new QLineEdit( this );
93 m_data->valueEdit->setReadOnly( false );
94 m_data->valueEdit->setValidator( new QDoubleValidator( m_data->valueEdit ) );
95 layout->addWidget( m_data->valueEdit );
96
97 connect( m_data->valueEdit, SIGNAL(editingFinished()), SLOT(textChanged()) );
98
99 layout->setStretchFactor( m_data->valueEdit, 10 );
100
101 for ( int i = 0; i < ButtonCnt; i++ )
102 {
103 QwtArrowButton* btn =
104 new QwtArrowButton( i + 1, Qt::UpArrow, this );
105 btn->setFocusPolicy( Qt::NoFocus );
106 layout->addWidget( btn );
107
108 connect( btn, SIGNAL(released()), SLOT(btnReleased()) );
109 connect( btn, SIGNAL(clicked()), SLOT(btnClicked()) );
110
111 m_data->buttonUp[i] = btn;
112 }
113
114 setNumButtons( 2 );
115 setRange( 0.0, 1.0 );
116 setSingleStep( 0.001 );
117 setValue( 0.0 );
118
119 setSizePolicy(
120 QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) );
121
122 setFocusProxy( m_data->valueEdit );
123 setFocusPolicy( Qt::StrongFocus );
124}
125
128{
129 delete m_data;
130}
131
142void QwtCounter::setValid( bool on )
143{
144 if ( on != m_data->isValid )
145 {
146 m_data->isValid = on;
147
148 updateButtons();
149
150 if ( m_data->isValid )
151 {
152 showNumber( value() );
153 Q_EMIT valueChanged( value() );
154 }
155 else
156 {
157 m_data->valueEdit->setText( QString() );
158 }
159 }
160}
161
167{
168 return m_data->isValid;
169}
170
178{
179 m_data->valueEdit->setReadOnly( on );
180}
181
187{
188 return m_data->valueEdit->isReadOnly();
189}
190
202void QwtCounter::setValue( double value )
203{
204 const double vmin = qwtMinF( m_data->minimum, m_data->maximum );
205 const double vmax = qwtMaxF( m_data->minimum, m_data->maximum );
206
207 value = qBound( vmin, value, vmax );
208
209 if ( !m_data->isValid || value != m_data->value )
210 {
211 m_data->isValid = true;
212 m_data->value = value;
213
214 showNumber( value );
215 updateButtons();
216
217 Q_EMIT valueChanged( value );
218 }
219}
220
225double QwtCounter::value() const
226{
227 return m_data->value;
228}
229
241void QwtCounter::setRange( double min, double max )
242{
243 max = qwtMaxF( min, max );
244
245 if ( m_data->maximum == max && m_data->minimum == min )
246 return;
247
248 m_data->minimum = min;
249 m_data->maximum = max;
250
252
253 const double value = qBound( min, m_data->value, max );
254
255 if ( value != m_data->value )
256 {
257 m_data->value = value;
258
259 if ( m_data->isValid )
260 {
261 showNumber( value );
262 Q_EMIT valueChanged( value );
263 }
264 }
265
266 updateButtons();
267}
268
277void QwtCounter::setMinimum( double value )
278{
279 setRange( value, maximum() );
280}
281
287{
288 return m_data->minimum;
289}
290
297void QwtCounter::setMaximum( double value )
298{
299 setRange( minimum(), value );
300}
301
307{
308 return m_data->maximum;
309}
310
319void QwtCounter::setSingleStep( double stepSize )
320{
321 m_data->singleStep = qwtMaxF( stepSize, 0.0 );
322}
323
329{
330 return m_data->singleStep;
331}
332
343{
344 m_data->wrapping = on;
345}
346
352{
353 return m_data->wrapping;
354}
355
362void QwtCounter::setNumButtons( int numButtons )
363{
364 if ( numButtons < 0 || numButtons > QwtCounter::ButtonCnt )
365 return;
366
367 for ( int i = 0; i < QwtCounter::ButtonCnt; i++ )
368 {
369 if ( i < numButtons )
370 {
371 m_data->buttonDown[i]->show();
372 m_data->buttonUp[i]->show();
373 }
374 else
375 {
376 m_data->buttonDown[i]->hide();
377 m_data->buttonUp[i]->hide();
378 }
379 }
380
381 m_data->numButtons = numButtons;
382}
383
389{
390 return m_data->numButtons;
391}
392
403void QwtCounter::setIncSteps( QwtCounter::Button button, int numSteps )
404{
405 if ( button >= 0 && button < QwtCounter::ButtonCnt )
406 m_data->increment[ button ] = numSteps;
407}
408
417{
418 if ( button >= 0 && button < QwtCounter::ButtonCnt )
419 return m_data->increment[ button ];
420
421 return 0;
422}
423
424
430{
432}
433
436{
438}
439
445{
447}
448
451{
453}
454
460{
462}
463
466{
468}
469
471void QwtCounter::textChanged()
472{
473 bool converted = false;
474
475 const double value = m_data->valueEdit->text().toDouble( &converted );
476 if ( converted )
477 setValue( value );
478}
479
485bool QwtCounter::event( QEvent* event )
486{
487 if ( event->type() == QEvent::PolishRequest )
488 {
489 const QFontMetrics fm = m_data->valueEdit->fontMetrics();
490
491 const int w = QwtPainter::horizontalAdvance( fm, "W" ) + 8;
492 for ( int i = 0; i < ButtonCnt; i++ )
493 {
494 m_data->buttonDown[i]->setMinimumWidth( w );
495 m_data->buttonUp[i]->setMinimumWidth( w );
496 }
497 }
498
499 return QWidget::event( event );
500}
501
524void QwtCounter::keyPressEvent ( QKeyEvent* event )
525{
526 bool accepted = true;
527
528 switch ( event->key() )
529 {
530 case Qt::Key_Home:
531 {
532 if ( event->modifiers() & Qt::ControlModifier )
533 setValue( minimum() );
534 else
535 accepted = false;
536 break;
537 }
538 case Qt::Key_End:
539 {
540 if ( event->modifiers() & Qt::ControlModifier )
541 setValue( maximum() );
542 else
543 accepted = false;
544 break;
545 }
546 case Qt::Key_Up:
547 {
548 incrementValue( m_data->increment[0] );
549 break;
550 }
551 case Qt::Key_Down:
552 {
553 incrementValue( -m_data->increment[0] );
554 break;
555 }
556 case Qt::Key_PageUp:
557 case Qt::Key_PageDown:
558 {
559 int increment = m_data->increment[0];
560 if ( m_data->numButtons >= 2 )
561 increment = m_data->increment[1];
562 if ( m_data->numButtons >= 3 )
563 {
564 if ( event->modifiers() & Qt::ShiftModifier )
565 increment = m_data->increment[2];
566 }
567 if ( event->key() == Qt::Key_PageDown )
568 increment = -increment;
569 incrementValue( increment );
570 break;
571 }
572 default:
573 {
574 accepted = false;
575 }
576 }
577
578 if ( accepted )
579 {
580 event->accept();
581 return;
582 }
583
584 QWidget::keyPressEvent ( event );
585}
586
591void QwtCounter::wheelEvent( QWheelEvent* event )
592{
593 event->accept();
594
595 if ( m_data->numButtons <= 0 )
596 return;
597
598 int increment = m_data->increment[0];
599 if ( m_data->numButtons >= 2 )
600 {
601 if ( event->modifiers() & Qt::ControlModifier )
602 increment = m_data->increment[1];
603 }
604 if ( m_data->numButtons >= 3 )
605 {
606 if ( event->modifiers() & Qt::ShiftModifier )
607 increment = m_data->increment[2];
608 }
609
610#if QT_VERSION < 0x050e00
611 const QPoint wheelPos = event->pos();
612 const int wheelDelta = event->delta();
613#else
614 const QPoint wheelPos = event->position().toPoint();
615
616 const QPoint delta = event->angleDelta();
617 const int wheelDelta = ( qAbs( delta.x() ) > qAbs( delta.y() ) )
618 ? delta.x() : delta.y();
619#endif
620
621 for ( int i = 0; i < m_data->numButtons; i++ )
622 {
623 if ( m_data->buttonDown[i]->geometry().contains( wheelPos ) ||
624 m_data->buttonUp[i]->geometry().contains( wheelPos ) )
625 {
626 increment = m_data->increment[i];
627 }
628 }
629
630 incrementValue( wheelDelta / 120 * increment );
631}
632
633void QwtCounter::incrementValue( int numSteps )
634{
635 const double min = m_data->minimum;
636 const double max = m_data->maximum;
637 double stepSize = m_data->singleStep;
638
639 if ( !m_data->isValid || min >= max || stepSize <= 0.0 )
640 return;
641
642
643#if 1
644 stepSize = qwtMaxF( stepSize, 1.0e-10 * ( max - min ) );
645#endif
646
647 double value = m_data->value + numSteps * stepSize;
648
649 if ( m_data->wrapping )
650 {
651 const double range = max - min;
652
653 if ( value < min )
654 {
655 value += std::ceil( ( min - value ) / range ) * range;
656 }
657 else if ( value > max )
658 {
659 value -= std::ceil( ( value - max ) / range ) * range;
660 }
661 }
662 else
663 {
664 value = qBound( min, value, max );
665 }
666
667 value = min + qRound( ( value - min ) / stepSize ) * stepSize;
668
669 if ( stepSize > 1e-12 )
670 {
671 if ( qFuzzyCompare( value + 1.0, 1.0 ) )
672 {
673 // correct rounding error if value = 0
674 value = 0.0;
675 }
676 else if ( qFuzzyCompare( value, max ) )
677 {
678 // correct rounding error at the border
679 value = max;
680 }
681 }
682
683 if ( value != m_data->value )
684 {
685 m_data->value = value;
686 showNumber( m_data->value );
687 updateButtons();
688
689 Q_EMIT valueChanged( m_data->value );
690 }
691}
692
693
702void QwtCounter::updateButtons()
703{
704 if ( m_data->isValid )
705 {
706 // 1. save enabled state of the smallest down- and up-button
707 // 2. change enabled state on under- or over-flow
708
709 for ( int i = 0; i < QwtCounter::ButtonCnt; i++ )
710 {
711 m_data->buttonDown[i]->setEnabled( value() > minimum() );
712 m_data->buttonUp[i]->setEnabled( value() < maximum() );
713 }
714 }
715 else
716 {
717 for ( int i = 0; i < QwtCounter::ButtonCnt; i++ )
718 {
719 m_data->buttonDown[i]->setEnabled( false );
720 m_data->buttonUp[i]->setEnabled( false );
721 }
722 }
723}
729void QwtCounter::showNumber( double number )
730{
731 QString text;
732 text.setNum( number );
733
734 const int cursorPos = m_data->valueEdit->cursorPosition();
735 m_data->valueEdit->setText( text );
736 m_data->valueEdit->setCursorPosition( cursorPos );
737}
738
740void QwtCounter::btnClicked()
741{
742 for ( int i = 0; i < ButtonCnt; i++ )
743 {
744 if ( m_data->buttonUp[i] == sender() )
745 incrementValue( m_data->increment[i] );
746
747 if ( m_data->buttonDown[i] == sender() )
748 incrementValue( -m_data->increment[i] );
749 }
750}
751
753void QwtCounter::btnReleased()
754{
755 Q_EMIT buttonReleased( value() );
756}
757
760{
761 QString tmp;
762
763 int w = tmp.setNum( minimum() ).length();
764 int w1 = tmp.setNum( maximum() ).length();
765 if ( w1 > w )
766 w = w1;
767 w1 = tmp.setNum( minimum() + singleStep() ).length();
768 if ( w1 > w )
769 w = w1;
770 w1 = tmp.setNum( maximum() - singleStep() ).length();
771 if ( w1 > w )
772 w = w1;
773
774 tmp.fill( '9', w );
775
776 w = QwtPainter::horizontalAdvance( m_data->valueEdit->fontMetrics(), tmp ) + 2;
777
778 if ( m_data->valueEdit->hasFrame() )
779 w += 2 * style()->pixelMetric( QStyle::PM_DefaultFrameWidth );
780
781 // Now we replace default sizeHint contribution of m_data->valueEdit by
782 // what we really need.
783
784 w += QWidget::sizeHint().width() - m_data->valueEdit->sizeHint().width();
785
786 const int h = qMin( QWidget::sizeHint().height(),
787 m_data->valueEdit->minimumSizeHint().height() );
788
789 return QSize( w, h );
790}
791
792#include "moc_qwt_counter.cpp"
Arrow Button.
Button
Button index.
Definition qwt_counter.h:68
@ Button1
Button intended for minor steps.
Definition qwt_counter.h:70
@ Button3
Button intended for large steps.
Definition qwt_counter.h:76
@ Button2
Button intended for medium steps.
Definition qwt_counter.h:73
@ ButtonCnt
Number of buttons.
Definition qwt_counter.h:79
void setStepButton2(int nSteps)
double minimum() const
double value() const
int stepButton3() const
returns the number of increment steps for button 3
void setValue(double)
Set a new value without adjusting to the step raster.
void setMinimum(double)
virtual QSize sizeHint() const override
A size hint.
bool isReadOnly() const
bool wrapping() const
bool isValid() const
virtual ~QwtCounter()
Destructor.
void buttonReleased(double value)
void setStepButton3(int nSteps)
double maximum() const
double singleStep() const
void setWrapping(bool)
En/Disable wrapping.
void setNumButtons(int)
int incSteps(QwtCounter::Button) const
virtual bool event(QEvent *) override
void setValid(bool)
int numButtons() const
virtual void keyPressEvent(QKeyEvent *) override
void setIncSteps(QwtCounter::Button, int numSteps)
int stepButton2() const
returns the number of increment steps for button 2
void setReadOnly(bool)
Allow/disallow the user to manually edit the value.
void setRange(double min, double max)
Set the minimum and maximum values.
void valueChanged(double value)
void setStepButton1(int nSteps)
QwtCounter(QWidget *parent=NULL)
void setSingleStep(double stepSize)
Set the step size of the counter.
void setMaximum(double)
virtual void wheelEvent(QWheelEvent *) override
int stepButton1() const
returns the number of increment steps for button 1
static int horizontalAdvance(const QFontMetrics &, const QString &)