source: ntrip/trunk/BNC/qwt/qwt_counter.cpp@ 10006

Last change on this file since 10006 was 9383, checked in by stoecker, 4 years ago

update to qwt verion 6.1.1 to fix build with newer Qt5

File size: 17.4 KB
Line 
1/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
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_math.h"
12#include "qwt_counter.h"
13#include <qlayout.h>
14#include <qlineedit.h>
15#include <qvalidator.h>
16#include <qevent.h>
17#include <qstyle.h>
18
19class QwtCounter::PrivateData
20{
21public:
22 PrivateData():
23 minimum( 0.0 ),
24 maximum( 0.0 ),
25 singleStep( 1.0 ),
26 isValid( false ),
27 value( 0.0 ),
28 wrapping( false )
29 {
30 increment[Button1] = 1;
31 increment[Button2] = 10;
32 increment[Button3] = 100;
33 }
34
35 QwtArrowButton *buttonDown[ButtonCnt];
36 QwtArrowButton *buttonUp[ButtonCnt];
37 QLineEdit *valueEdit;
38
39 int increment[ButtonCnt];
40 int numButtons;
41
42 double minimum;
43 double maximum;
44 double singleStep;
45
46 bool isValid;
47 double value;
48
49 bool wrapping;
50};
51
52/*!
53 The counter is initialized with a range is set to [0.0, 1.0] with
54 0.01 as single step size. The value is invalid.
55
56 The default number of buttons is set to 2. The default increments are:
57 \li Button 1: 1 step
58 \li Button 2: 10 steps
59 \li Button 3: 100 steps
60
61 \param parent
62 */
63QwtCounter::QwtCounter( QWidget *parent ):
64 QWidget( parent )
65{
66 initCounter();
67}
68
69void QwtCounter::initCounter()
70{
71 d_data = new PrivateData;
72
73 QHBoxLayout *layout = new QHBoxLayout( this );
74 layout->setSpacing( 0 );
75 layout->setMargin( 0 );
76
77 for ( int i = ButtonCnt - 1; i >= 0; i-- )
78 {
79 QwtArrowButton *btn =
80 new QwtArrowButton( i + 1, Qt::DownArrow, this );
81 btn->setFocusPolicy( Qt::NoFocus );
82 btn->installEventFilter( this );
83 layout->addWidget( btn );
84
85 connect( btn, SIGNAL(released()), SLOT(btnReleased()) );
86 connect( btn, SIGNAL(clicked()), SLOT(btnClicked()) );
87
88 d_data->buttonDown[i] = btn;
89 }
90
91 d_data->valueEdit = new QLineEdit( this );
92 d_data->valueEdit->setReadOnly( false );
93 d_data->valueEdit->setValidator( new QDoubleValidator( d_data->valueEdit ) );
94 layout->addWidget( d_data->valueEdit );
95
96 connect( d_data->valueEdit, SIGNAL(editingFinished()), SLOT(textChanged()) );
97
98 layout->setStretchFactor( d_data->valueEdit, 10 );
99
100 for ( int i = 0; i < ButtonCnt; i++ )
101 {
102 QwtArrowButton *btn =
103 new QwtArrowButton( i + 1, Qt::UpArrow, this );
104 btn->setFocusPolicy( Qt::NoFocus );
105 btn->installEventFilter( this );
106 layout->addWidget( btn );
107
108 connect( btn, SIGNAL(released()), SLOT(btnReleased()) );
109 connect( btn, SIGNAL(clicked()), SLOT(btnClicked()) );
110
111 d_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( d_data->valueEdit );
123 setFocusPolicy( Qt::StrongFocus );
124}
125
126//! Destructor
127QwtCounter::~QwtCounter()
128{
129 delete d_data;
130}
131
132/*!
133 Set the counter to be in valid/invalid state
134
135 When the counter is set to invalid, no numbers are displayed and
136 the buttons are disabled.
137
138 \param on If true the counter will be set as valid
139
140 \sa setValue(), isValid()
141*/
142void QwtCounter::setValid( bool on )
143{
144 if ( on != d_data->isValid )
145 {
146 d_data->isValid = on;
147
148 updateButtons();
149
150 if ( d_data->isValid )
151 {
152 showNumber( value() );
153 Q_EMIT valueChanged( value() );
154 }
155 else
156 {
157 d_data->valueEdit->setText( QString() );
158 }
159 }
160}
161
162/*!
163 \return True, if the value is valid
164 \sa setValid(), setValue()
165 */
166bool QwtCounter::isValid() const
167{
168 return d_data->isValid;
169}
170
171/*!
172 \brief Allow/disallow the user to manually edit the value
173
174 \param on True disable editing
175 \sa isReadOnly()
176*/
177void QwtCounter::setReadOnly( bool on )
178{
179 d_data->valueEdit->setReadOnly( on );
180}
181
182/*!
183 \return True, when the line line edit is read only. (default is no)
184 \sa setReadOnly()
185 */
186bool QwtCounter::isReadOnly() const
187{
188 return d_data->valueEdit->isReadOnly();
189}
190
191/*!
192 \brief Set a new value without adjusting to the step raster
193
194 The state of the counter is set to be valid.
195
196 \param value New value
197
198 \sa isValid(), value(), valueChanged()
199 \warning The value is clipped when it lies outside the range.
200*/
201
202void QwtCounter::setValue( double value )
203{
204 const double vmin = qMin( d_data->minimum, d_data->maximum );
205 const double vmax = qMax( d_data->minimum, d_data->maximum );
206
207 value = qBound( vmin, value, vmax );
208
209 if ( !d_data->isValid || value != d_data->value )
210 {
211 d_data->isValid = true;
212 d_data->value = value;
213
214 showNumber( value );
215 updateButtons();
216
217 Q_EMIT valueChanged( value );
218 }
219}
220
221/*!
222 \return Current value of the counter
223 \sa setValue(), valueChanged()
224 */
225double QwtCounter::value() const
226{
227 return d_data->value;
228}
229
230/*!
231 \brief Set the minimum and maximum values
232
233 The maximum is adjusted if necessary to ensure that the range remains valid.
234 The value might be modified to be inside of the range.
235
236 \param min Minimum value
237 \param max Maximum value
238
239 \sa minimum(), maximum()
240 */
241void QwtCounter::setRange( double min, double max )
242{
243 max = qMax( min, max );
244
245 if ( d_data->maximum == max && d_data->minimum == min )
246 return;
247
248 d_data->minimum = min;
249 d_data->maximum = max;
250
251 setSingleStep( singleStep() );
252
253 const double value = qBound( min, d_data->value, max );
254
255 if ( value != d_data->value )
256 {
257 d_data->value = value;
258
259 if ( d_data->isValid )
260 {
261 showNumber( value );
262 Q_EMIT valueChanged( value );
263 }
264 }
265
266 updateButtons();
267}
268
269/*!
270 Set the minimum value of the range
271
272 \param value Minimum value
273 \sa setRange(), setMaximum(), minimum()
274
275 \note The maximum is adjusted if necessary to ensure that the range remains valid.
276*/
277void QwtCounter::setMinimum( double value )
278{
279 setRange( value, maximum() );
280}
281
282/*!
283 \return The minimum of the range
284 \sa setRange(), setMinimum(), maximum()
285*/
286double QwtCounter::minimum() const
287{
288 return d_data->minimum;
289}
290
291/*!
292 Set the maximum value of the range
293
294 \param value Maximum value
295 \sa setRange(), setMinimum(), maximum()
296*/
297void QwtCounter::setMaximum( double value )
298{
299 setRange( minimum(), value );
300}
301
302/*!
303 \return The maximum of the range
304 \sa setRange(), setMaximum(), minimum()
305*/
306double QwtCounter::maximum() const
307{
308 return d_data->maximum;
309}
310
311/*!
312 \brief Set the step size of the counter
313
314 A value <= 0.0 disables stepping
315
316 \param stepSize Single step size
317 \sa singleStep()
318*/
319void QwtCounter::setSingleStep( double stepSize )
320{
321 d_data->singleStep = qMax( stepSize, 0.0 );
322}
323
324/*!
325 \return Single step size
326 \sa setSingleStep()
327 */
328double QwtCounter::singleStep() const
329{
330 return d_data->singleStep;
331}
332
333/*!
334 \brief En/Disable wrapping
335
336 If wrapping is true stepping up from maximum() value will take
337 you to the minimum() value and vice versa.
338
339 \param on En/Disable wrapping
340 \sa wrapping()
341 */
342void QwtCounter::setWrapping( bool on )
343{
344 d_data->wrapping = on;
345}
346
347/*!
348 \return True, when wrapping is set
349 \sa setWrapping()
350 */
351bool QwtCounter::wrapping() const
352{
353 return d_data->wrapping;
354}
355
356/*!
357 Specify the number of buttons on each side of the label
358
359 \param numButtons Number of buttons
360 \sa numButtons()
361*/
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 d_data->buttonDown[i]->show();
372 d_data->buttonUp[i]->show();
373 }
374 else
375 {
376 d_data->buttonDown[i]->hide();
377 d_data->buttonUp[i]->hide();
378 }
379 }
380
381 d_data->numButtons = numButtons;
382}
383
384/*!
385 \return The number of buttons on each side of the widget.
386 \sa setNumButtons()
387*/
388int QwtCounter::numButtons() const
389{
390 return d_data->numButtons;
391}
392
393/*!
394 Specify the number of steps by which the value
395 is incremented or decremented when a specified button
396 is pushed.
397
398 \param button Button index
399 \param numSteps Number of steps
400
401 \sa incSteps()
402*/
403void QwtCounter::setIncSteps( QwtCounter::Button button, int numSteps )
404{
405 if ( button >= 0 && button < QwtCounter::ButtonCnt )
406 d_data->increment[ button ] = numSteps;
407}
408
409/*!
410 \return The number of steps by which a specified button increments the value
411 or 0 if the button is invalid.
412 \param button Button index
413
414 \sa setIncSteps()
415*/
416int QwtCounter::incSteps( QwtCounter::Button button ) const
417{
418 if ( button >= 0 && button < QwtCounter::ButtonCnt )
419 return d_data->increment[ button ];
420
421 return 0;
422}
423
424
425/*!
426 Set the number of increment steps for button 1
427 \param nSteps Number of steps
428*/
429void QwtCounter::setStepButton1( int nSteps )
430{
431 setIncSteps( QwtCounter::Button1, nSteps );
432}
433
434//! returns the number of increment steps for button 1
435int QwtCounter::stepButton1() const
436{
437 return incSteps( QwtCounter::Button1 );
438}
439
440/*!
441 Set the number of increment steps for button 2
442 \param nSteps Number of steps
443*/
444void QwtCounter::setStepButton2( int nSteps )
445{
446 setIncSteps( QwtCounter::Button2, nSteps );
447}
448
449//! returns the number of increment steps for button 2
450int QwtCounter::stepButton2() const
451{
452 return incSteps( QwtCounter::Button2 );
453}
454
455/*!
456 Set the number of increment steps for button 3
457 \param nSteps Number of steps
458*/
459void QwtCounter::setStepButton3( int nSteps )
460{
461 setIncSteps( QwtCounter::Button3, nSteps );
462}
463
464//! returns the number of increment steps for button 3
465int QwtCounter::stepButton3() const
466{
467 return incSteps( QwtCounter::Button3 );
468}
469
470//! Set from lineedit
471void QwtCounter::textChanged()
472{
473 bool converted = false;
474
475 const double value = d_data->valueEdit->text().toDouble( &converted );
476 if ( converted )
477 setValue( value );
478}
479
480/*!
481 Handle QEvent::PolishRequest events
482 \param event Event
483 \return see QWidget::event()
484*/
485bool QwtCounter::event( QEvent *event )
486{
487 if ( event->type() == QEvent::PolishRequest )
488 {
489 const int w = d_data->valueEdit->fontMetrics().width( "W" ) + 8;
490 for ( int i = 0; i < ButtonCnt; i++ )
491 {
492 d_data->buttonDown[i]->setMinimumWidth( w );
493 d_data->buttonUp[i]->setMinimumWidth( w );
494 }
495 }
496
497 return QWidget::event( event );
498}
499
500/*!
501 Handle key events
502
503 - Ctrl + Qt::Key_Home\n
504 Step to minimum()
505 - Ctrl + Qt::Key_End\n
506 Step to maximum()
507 - Qt::Key_Up\n
508 Increment by incSteps(QwtCounter::Button1)
509 - Qt::Key_Down\n
510 Decrement by incSteps(QwtCounter::Button1)
511 - Qt::Key_PageUp\n
512 Increment by incSteps(QwtCounter::Button2)
513 - Qt::Key_PageDown\n
514 Decrement by incSteps(QwtCounter::Button2)
515 - Shift + Qt::Key_PageUp\n
516 Increment by incSteps(QwtCounter::Button3)
517 - Shift + Qt::Key_PageDown\n
518 Decrement by incSteps(QwtCounter::Button3)
519
520 \param event Key event
521*/
522void QwtCounter::keyPressEvent ( QKeyEvent *event )
523{
524 bool accepted = true;
525
526 switch ( event->key() )
527 {
528 case Qt::Key_Home:
529 {
530 if ( event->modifiers() & Qt::ControlModifier )
531 setValue( minimum() );
532 else
533 accepted = false;
534 break;
535 }
536 case Qt::Key_End:
537 {
538 if ( event->modifiers() & Qt::ControlModifier )
539 setValue( maximum() );
540 else
541 accepted = false;
542 break;
543 }
544 case Qt::Key_Up:
545 {
546 incrementValue( d_data->increment[0] );
547 break;
548 }
549 case Qt::Key_Down:
550 {
551 incrementValue( -d_data->increment[0] );
552 break;
553 }
554 case Qt::Key_PageUp:
555 case Qt::Key_PageDown:
556 {
557 int increment = d_data->increment[0];
558 if ( d_data->numButtons >= 2 )
559 increment = d_data->increment[1];
560 if ( d_data->numButtons >= 3 )
561 {
562 if ( event->modifiers() & Qt::ShiftModifier )
563 increment = d_data->increment[2];
564 }
565 if ( event->key() == Qt::Key_PageDown )
566 increment = -increment;
567 incrementValue( increment );
568 break;
569 }
570 default:
571 {
572 accepted = false;
573 }
574 }
575
576 if ( accepted )
577 {
578 event->accept();
579 return;
580 }
581
582 QWidget::keyPressEvent ( event );
583}
584
585/*!
586 Handle wheel events
587 \param event Wheel event
588*/
589void QwtCounter::wheelEvent( QWheelEvent *event )
590{
591 event->accept();
592
593 if ( d_data->numButtons <= 0 )
594 return;
595
596 int increment = d_data->increment[0];
597 if ( d_data->numButtons >= 2 )
598 {
599 if ( event->modifiers() & Qt::ControlModifier )
600 increment = d_data->increment[1];
601 }
602 if ( d_data->numButtons >= 3 )
603 {
604 if ( event->modifiers() & Qt::ShiftModifier )
605 increment = d_data->increment[2];
606 }
607
608 for ( int i = 0; i < d_data->numButtons; i++ )
609 {
610 if ( d_data->buttonDown[i]->geometry().contains( event->pos() ) ||
611 d_data->buttonUp[i]->geometry().contains( event->pos() ) )
612 {
613 increment = d_data->increment[i];
614 }
615 }
616
617 const int wheel_delta = 120;
618
619#if 1
620 int delta = event->delta();
621 if ( delta >= 2 * wheel_delta )
622 delta /= 2; // Never saw an abs(delta) < 240
623#endif
624
625 incrementValue( delta / wheel_delta * increment );
626}
627
628void QwtCounter::incrementValue( int numSteps )
629{
630 const double min = d_data->minimum;
631 const double max = d_data->maximum;
632 double stepSize = d_data->singleStep;
633
634 if ( !d_data->isValid || min >= max || stepSize <= 0.0 )
635 return;
636
637
638#if 1
639 stepSize = qMax( stepSize, 1.0e-10 * ( max - min ) );
640#endif
641
642 double value = d_data->value + numSteps * stepSize;
643
644 if ( d_data->wrapping )
645 {
646 const double range = max - min;
647
648 if ( value < min )
649 {
650 value += ::ceil( ( min - value ) / range ) * range;
651 }
652 else if ( value > max )
653 {
654 value -= ::ceil( ( value - max ) / range ) * range;
655 }
656 }
657 else
658 {
659 value = qBound( min, value, max );
660 }
661
662 value = min + qRound( ( value - min ) / stepSize ) * stepSize;
663
664 if ( stepSize > 1e-12 )
665 {
666 if ( qFuzzyCompare( value + 1.0, 1.0 ) )
667 {
668 // correct rounding error if value = 0
669 value = 0.0;
670 }
671 else if ( qFuzzyCompare( value, max ) )
672 {
673 // correct rounding error at the border
674 value = max;
675 }
676 }
677
678 if ( value != d_data->value )
679 {
680 d_data->value = value;
681 showNumber( d_data->value );
682 updateButtons();
683
684 Q_EMIT valueChanged( d_data->value );
685 }
686}
687
688
689/*!
690 \brief Update buttons according to the current value
691
692 When the QwtCounter under- or over-flows, the focus is set to the smallest
693 up- or down-button and counting is disabled.
694
695 Counting is re-enabled on a button release event (mouse or space bar).
696*/
697void QwtCounter::updateButtons()
698{
699 if ( d_data->isValid )
700 {
701 // 1. save enabled state of the smallest down- and up-button
702 // 2. change enabled state on under- or over-flow
703
704 for ( int i = 0; i < QwtCounter::ButtonCnt; i++ )
705 {
706 d_data->buttonDown[i]->setEnabled( value() > minimum() );
707 d_data->buttonUp[i]->setEnabled( value() < maximum() );
708 }
709 }
710 else
711 {
712 for ( int i = 0; i < QwtCounter::ButtonCnt; i++ )
713 {
714 d_data->buttonDown[i]->setEnabled( false );
715 d_data->buttonUp[i]->setEnabled( false );
716 }
717 }
718}
719/*!
720 Display number string
721
722 \param number Number
723*/
724void QwtCounter::showNumber( double number )
725{
726 QString text;
727 text.setNum( number );
728
729 const int cursorPos = d_data->valueEdit->cursorPosition();
730 d_data->valueEdit->setText( text );
731 d_data->valueEdit->setCursorPosition( cursorPos );
732}
733
734//! Button clicked
735void QwtCounter::btnClicked()
736{
737 for ( int i = 0; i < ButtonCnt; i++ )
738 {
739 if ( d_data->buttonUp[i] == sender() )
740 incrementValue( d_data->increment[i] );
741
742 if ( d_data->buttonDown[i] == sender() )
743 incrementValue( -d_data->increment[i] );
744 }
745}
746
747//! Button released
748void QwtCounter::btnReleased()
749{
750 Q_EMIT buttonReleased( value() );
751}
752
753//! A size hint
754QSize QwtCounter::sizeHint() const
755{
756 QString tmp;
757
758 int w = tmp.setNum( minimum() ).length();
759 int w1 = tmp.setNum( maximum() ).length();
760 if ( w1 > w )
761 w = w1;
762 w1 = tmp.setNum( minimum() + singleStep() ).length();
763 if ( w1 > w )
764 w = w1;
765 w1 = tmp.setNum( maximum() - singleStep() ).length();
766 if ( w1 > w )
767 w = w1;
768
769 tmp.fill( '9', w );
770
771 QFontMetrics fm( d_data->valueEdit->font() );
772 w = fm.width( tmp ) + 2;
773 if ( d_data->valueEdit->hasFrame() )
774 w += 2 * style()->pixelMetric( QStyle::PM_DefaultFrameWidth );
775
776 // Now we replace default sizeHint contribution of d_data->valueEdit by
777 // what we really need.
778
779 w += QWidget::sizeHint().width() - d_data->valueEdit->sizeHint().width();
780
781 const int h = qMin( QWidget::sizeHint().height(),
782 d_data->valueEdit->minimumSizeHint().height() );
783 return QSize( w, h );
784}
Note: See TracBrowser for help on using the repository browser.