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

Last change on this file since 9184 was 8127, checked in by stoecker, 7 years ago

update qwt and qwtpolar, many QT5 fixes (unfinished)

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