Qwt User's Guide: qwt_abstract_slider.cpp Source File

Qwt User's Guide 6.2.0

qwt_abstract_slider.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_abstract_slider.h"
11 #include "qwt_scale_map.h"
12 #include "qwt_scale_div.h"
13 #include "qwt_math.h"
14
15 #include <qevent.h>
16
17 static double qwtAlignToScaleDiv(
18 const QwtAbstractSlider* slider, double value )
19 {
20 const QwtScaleDiv& sd = slider->scaleDiv();
21
22 const int tValue = slider->transform( value );
23
24 if ( tValue == slider->transform( sd.lowerBound() ) )
25 return sd.lowerBound();
26
27 if ( tValue == slider->transform( sd.upperBound() ) )
28 return sd.upperBound();
29
30 for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ )
31 {
32 const QList< double > ticks = sd.ticks( i );
33 for ( int j = 0; j < ticks.size(); j++ )
34 {
35 if ( slider->transform( ticks[ j ] ) == tValue )
36 return ticks[ j ];
37 }
38 }
39
40 return value;
41 }
42
43 class QwtAbstractSlider::PrivateData
44 {
45 public:
46 PrivateData()
47 : isScrolling( false )
48 , isTracking( true )
49 , pendingValueChanged( false )
50 , readOnly( false )
51 , totalSteps( 100 )
52 , singleSteps( 1 )
53 , pageSteps( 10 )
54 , stepAlignment( true )
55 , isValid( false )
56 , value( 0.0 )
57 , wrapping( false )
58 , invertedControls( false )
59 {
60 }
61
62 bool isScrolling;
63 bool isTracking;
64 bool pendingValueChanged;
65
66 bool readOnly;
67
68 uint totalSteps;
69 uint singleSteps;
70 uint pageSteps;
71 bool stepAlignment;
72
73 bool isValid;
74 double value;
75
76 bool wrapping;
77 bool invertedControls;
78 };
79
91 QwtAbstractSlider::QwtAbstractSlider( QWidget* parent )
92 : QwtAbstractScale( parent )
93 {
94 m_data = new QwtAbstractSlider::PrivateData;
95
96 setScale( 0.0, 100.0 );
97 setFocusPolicy( Qt::StrongFocus );
98 }
99
101 QwtAbstractSlider::~QwtAbstractSlider()
102 {
103 delete m_data;
104 }
105
113 void QwtAbstractSlider::setValid( bool on )
114 {
115 if ( on != m_data->isValid )
116 {
117 m_data->isValid = on;
118 sliderChange();
119
120 Q_EMIT valueChanged( m_data->value );
121 }
122 }
123
125 bool QwtAbstractSlider::isValid() const
126 {
127 return m_data->isValid;
128 }
129
141 void QwtAbstractSlider::setReadOnly( bool on )
142 {
143 if ( m_data->readOnly != on )
144 {
145 m_data->readOnly = on;
146 setFocusPolicy( on ? Qt::StrongFocus : Qt::NoFocus );
147
148 update();
149 }
150 }
151
159 bool QwtAbstractSlider::isReadOnly() const
160 {
161 return m_data->readOnly;
162 }
163
177 void QwtAbstractSlider::setTracking( bool on )
178 {
179 m_data->isTracking = on;
180 }
181
186 bool QwtAbstractSlider::isTracking() const
187 {
188 return m_data->isTracking;
189 }
190
195 void QwtAbstractSlider::mousePressEvent( QMouseEvent* event )
196 {
197 if ( isReadOnly() )
198 {
199 event->ignore();
200 return;
201 }
202
203 if ( !m_data->isValid || lowerBound() == upperBound() )
204 return;
205
206 m_data->isScrolling = isScrollPosition( event->pos() );
207
208 if ( m_data->isScrolling )
209 {
210 m_data->pendingValueChanged = false;
211
212 Q_EMIT sliderPressed();
213 }
214 }
215
220 void QwtAbstractSlider::mouseMoveEvent( QMouseEvent* event )
221 {
222 if ( isReadOnly() )
223 {
224 event->ignore();
225 return;
226 }
227
228 if ( m_data->isValid && m_data->isScrolling )
229 {
230 double value = scrolledTo( event->pos() );
231 if ( value != m_data->value )
232 {
233 value = boundedValue( value );
234
235 if ( m_data->stepAlignment )
236 {
237 value = alignedValue( value );
238 }
239 else
240 {
241 value = qwtAlignToScaleDiv( this, value );
242 }
243
244 if ( value != m_data->value )
245 {
246 m_data->value = value;
247
248 sliderChange();
249
250 Q_EMIT sliderMoved( m_data->value );
251
252 if ( m_data->isTracking )
253 Q_EMIT valueChanged( m_data->value );
254 else
255 m_data->pendingValueChanged = true;
256 }
257 }
258 }
259 }
260
265 void QwtAbstractSlider::mouseReleaseEvent( QMouseEvent* event )
266 {
267 if ( isReadOnly() )
268 {
269 event->ignore();
270 return;
271 }
272
273 if ( m_data->isScrolling && m_data->isValid )
274 {
275 m_data->isScrolling = false;
276
277 if ( m_data->pendingValueChanged )
278 Q_EMIT valueChanged( m_data->value );
279
280 Q_EMIT sliderReleased();
281 }
282 }
283
296 void QwtAbstractSlider::wheelEvent( QWheelEvent* event )
297 {
298 if ( isReadOnly() )
299 {
300 event->ignore();
301 return;
302 }
303
304 if ( !m_data->isValid || m_data->isScrolling )
305 return;
306
307 #if QT_VERSION < 0x050000
308 const int wheelDelta = event->delta();
309 #else
310 const QPoint delta = event->angleDelta();
311 const int wheelDelta = ( qAbs( delta.x() ) > qAbs( delta.y() ) )
312 ? delta.x() : delta.y();
313 #endif
314
315 int numSteps = 0;
316
317 if ( ( event->modifiers() & Qt::ControlModifier ) ||
318 ( event->modifiers() & Qt::ShiftModifier ) )
319 {
320 // one page regardless of delta
321 numSteps = m_data->pageSteps;
322 if ( wheelDelta < 0 )
323 numSteps = -numSteps;
324 }
325 else
326 {
327 const int numTurns = ( wheelDelta / 120 );
328 numSteps = numTurns * m_data->singleSteps;
329 }
330
331 if ( m_data->invertedControls )
332 numSteps = -numSteps;
333
334 const double value = incrementedValue( m_data->value, numSteps );
335 if ( value != m_data->value )
336 {
337 m_data->value = value;
338 sliderChange();
339
340 Q_EMIT sliderMoved( m_data->value );
341 Q_EMIT valueChanged( m_data->value );
342 }
343 }
344
370 void QwtAbstractSlider::keyPressEvent( QKeyEvent* event )
371 {
372 if ( isReadOnly() )
373 {
374 event->ignore();
375 return;
376 }
377
378 if ( !m_data->isValid || m_data->isScrolling )
379 return;
380
381 int numSteps = 0;
382 double value = m_data->value;
383
384 switch ( event->key() )
385 {
386 case Qt::Key_Left:
387 {
388 numSteps = -static_cast< int >( m_data->singleSteps );
389 if ( isInverted() )
390 numSteps = -numSteps;
391
392 break;
393 }
394 case Qt::Key_Right:
395 {
396 numSteps = m_data->singleSteps;
397 if ( isInverted() )
398 numSteps = -numSteps;
399
400 break;
401 }
402 case Qt::Key_Down:
403 {
404 numSteps = -static_cast< int >( m_data->singleSteps );
405 if ( m_data->invertedControls )
406 numSteps = -numSteps;
407 break;
408 }
409 case Qt::Key_Up:
410 {
411 numSteps = m_data->singleSteps;
412 if ( m_data->invertedControls )
413 numSteps = -numSteps;
414
415 break;
416 }
417 case Qt::Key_PageUp:
418 {
419 numSteps = m_data->pageSteps;
420 if ( m_data->invertedControls )
421 numSteps = -numSteps;
422 break;
423 }
424 case Qt::Key_PageDown:
425 {
426 numSteps = -static_cast< int >( m_data->pageSteps );
427 if ( m_data->invertedControls )
428 numSteps = -numSteps;
429 break;
430 }
431 case Qt::Key_Home:
432 {
433 value = minimum();
434 break;
435 }
436 case Qt::Key_End:
437 {
438 value = maximum();
439 break;
440 }
441 default:
442 {
443 event->ignore();
444 }
445 }
446
447 if ( numSteps != 0 )
448 {
449 value = incrementedValue( m_data->value, numSteps );
450 }
451
452 if ( value != m_data->value )
453 {
454 m_data->value = value;
455 sliderChange();
456
457 Q_EMIT sliderMoved( m_data->value );
458 Q_EMIT valueChanged( m_data->value );
459 }
460 }
461
474 void QwtAbstractSlider::setTotalSteps( uint stepCount )
475 {
476 m_data->totalSteps = stepCount;
477 }
478
483 uint QwtAbstractSlider::totalSteps() const
484 {
485 return m_data->totalSteps;
486 }
487
499 void QwtAbstractSlider::setSingleSteps( uint stepCount )
500 {
501 m_data->singleSteps = stepCount;
502 }
503
508 uint QwtAbstractSlider::singleSteps() const
509 {
510 return m_data->singleSteps;
511 }
512
524 void QwtAbstractSlider::setPageSteps( uint stepCount )
525 {
526 m_data->pageSteps = stepCount;
527 }
528
533 uint QwtAbstractSlider::pageSteps() const
534 {
535 return m_data->pageSteps;
536 }
537
547 void QwtAbstractSlider::setStepAlignment( bool on )
548 {
549 if ( on != m_data->stepAlignment )
550 {
551 m_data->stepAlignment = on;
552 }
553 }
554
559 bool QwtAbstractSlider::stepAlignment() const
560 {
561 return m_data->stepAlignment;
562 }
563
570 void QwtAbstractSlider::setValue( double value )
571 {
572 value = qBound( minimum(), value, maximum() );
573
574 const bool changed = ( m_data->value != value ) || !m_data->isValid;
575
576 m_data->value = value;
577 m_data->isValid = true;
578
579 if ( changed )
580 {
581 sliderChange();
582 Q_EMIT valueChanged( m_data->value );
583 }
584 }
585
587 double QwtAbstractSlider::value() const
588 {
589 return m_data->value;
590 }
591
599 void QwtAbstractSlider::setWrapping( bool on )
600 {
601 m_data->wrapping = on;
602 }
603
608 bool QwtAbstractSlider::wrapping() const
609 {
610 return m_data->wrapping;
611 }
612
628 void QwtAbstractSlider::setInvertedControls( bool on )
629 {
630 m_data->invertedControls = on;
631 }
632
637 bool QwtAbstractSlider::invertedControls() const
638 {
639 return m_data->invertedControls;
640 }
641
650 void QwtAbstractSlider::incrementValue( int stepCount )
651 {
652 const double value = incrementedValue(
653 m_data->value, stepCount );
654
655 if ( value != m_data->value )
656 {
657 m_data->value = value;
658 sliderChange();
659 }
660 }
661
670 double QwtAbstractSlider::incrementedValue(
671 double value, int stepCount ) const
672 {
673 if ( m_data->totalSteps == 0 )
674 return value;
675
676 const QwtTransform* transformation =
677 scaleMap().transformation();
678
679 if ( transformation == NULL )
680 {
681 const double range = maximum() - minimum();
682 value += stepCount * range / m_data->totalSteps;
683 }
684 else
685 {
686 QwtScaleMap map = scaleMap();
687 map.setPaintInterval( 0, m_data->totalSteps );
688
689 // we need equidistant steps according to
690 // paint device coordinates
691 const double range = transformation->transform( maximum() )
692 - transformation->transform( minimum() );
693
694 const double stepSize = range / m_data->totalSteps;
695
696 double v = transformation->transform( value );
697
698 v = qRound( v / stepSize ) * stepSize;
699 v += stepCount * range / m_data->totalSteps;
700
701 value = transformation->invTransform( v );
702 }
703
704 value = boundedValue( value );
705
706 if ( m_data->stepAlignment )
707 value = alignedValue( value );
708
709 return value;
710 }
711
712 double QwtAbstractSlider::boundedValue( double value ) const
713 {
714 const double vmin = minimum();
715 const double vmax = maximum();
716
717 if ( m_data->wrapping && vmin != vmax )
718 {
719 if ( qFuzzyCompare( scaleMap().pDist(), 360.0 ) )
720 {
721 // full circle scales: min and max are the same
722
723 if ( qFuzzyCompare( value, vmax ) )
724 {
725 value = vmin;
726 }
727 else
728 {
729 const double range = vmax - vmin;
730
731 if ( value < vmin )
732 {
733 value += std::ceil( ( vmin - value ) / range ) * range;
734 }
735 else if ( value > vmax )
736 {
737 value -= std::ceil( ( value - vmax ) / range ) * range;
738 }
739 }
740 }
741 else
742 {
743 if ( value < vmin )
744 value = vmax;
745 else if ( value > vmax )
746 value = vmin;
747 }
748 }
749 else
750 {
751 value = qBound( vmin, value, vmax );
752 }
753
754 return value;
755 }
756
757 double QwtAbstractSlider::alignedValue( double value ) const
758 {
759 if ( m_data->totalSteps == 0 )
760 return value;
761
762 double stepSize;
763
764 if ( scaleMap().transformation() == NULL )
765 {
766 stepSize = ( maximum() - minimum() ) / m_data->totalSteps;
767 if ( stepSize > 0.0 )
768 {
769 value = lowerBound() +
770 qRound( ( value - lowerBound() ) / stepSize ) * stepSize;
771 }
772 }
773 else
774 {
775 stepSize = ( scaleMap().p2() - scaleMap().p1() ) / m_data->totalSteps;
776
777 if ( stepSize > 0.0 )
778 {
779 double v = scaleMap().transform( value );
780
781 v = scaleMap().p1() +
782 qRound( ( v - scaleMap().p1() ) / stepSize ) * stepSize;
783
784 value = scaleMap().invTransform( v );
785 }
786 }
787
788 if ( qAbs( stepSize ) > 1e-12 )
789 {
790 if ( qFuzzyCompare( value + 1.0, 1.0 ) )
791 {
792 // correct rounding error if value = 0
793 value = 0.0;
794 }
795 else
796 {
797 // correct rounding error at the border
798 if ( qFuzzyCompare( value, upperBound() ) )
799 value = upperBound();
800 else if ( qFuzzyCompare( value, lowerBound() ) )
801 value = lowerBound();
802 }
803 }
804
805 return value;
806 }
807
811 void QwtAbstractSlider::scaleChange()
812 {
813 const double value = qBound( minimum(), m_data->value, maximum() );
814
815 const bool changed = ( value != m_data->value );
816 if ( changed )
817 {
818 m_data->value = value;
819 }
820
821 if ( m_data->isValid || changed )
822 Q_EMIT valueChanged( m_data->value );
823
824 updateGeometry();
825 update();
826 }
827
829 void QwtAbstractSlider::sliderChange()
830 {
831 update();
832 }
833
834 #if QWT_MOC_INCLUDE
835 #include "moc_qwt_abstract_slider.cpp"
836 #endif
QList< double >
QwtAbstractScale
An abstract base class for widgets having a scale.
Definition: qwt_abstract_scale.h:37
QwtAbstractScale::scaleMap
const QwtScaleMap & scaleMap() const
Definition: qwt_abstract_scale.cpp:357
QwtAbstractScale::lowerBound
double lowerBound() const
Definition: qwt_abstract_scale.cpp:88
QwtAbstractScale::scaleDiv
const QwtScaleDiv & scaleDiv() const
Definition: qwt_abstract_scale.cpp:349
QwtAbstractScale::transform
int transform(double) const
Definition: qwt_abstract_scale.cpp:369
QwtAbstractScale::minimum
double minimum() const
Definition: qwt_abstract_scale.cpp:399
QwtAbstractScale::isInverted
bool isInverted() const
Definition: qwt_abstract_scale.cpp:390
QwtAbstractScale::maximum
double maximum() const
Definition: qwt_abstract_scale.cpp:409
QwtAbstractScale::upperBound
double upperBound() const
Definition: qwt_abstract_scale.cpp:111
QwtAbstractScale::setScale
void setScale(double lowerBound, double upperBound)
Specify a scale.
Definition: qwt_abstract_scale.cpp:130
QwtAbstractSlider
An abstract base class for slider widgets with a scale.
Definition: qwt_abstract_slider.h:33
QwtAbstractSlider::invertedControls
bool invertedControls() const
Definition: qwt_abstract_slider.cpp:637
QwtAbstractSlider::scaleChange
virtual void scaleChange() override
Definition: qwt_abstract_slider.cpp:811
QwtAbstractSlider::mouseReleaseEvent
virtual void mouseReleaseEvent(QMouseEvent *) override
Definition: qwt_abstract_slider.cpp:265
QwtAbstractSlider::~QwtAbstractSlider
virtual ~QwtAbstractSlider()
Destructor.
Definition: qwt_abstract_slider.cpp:101
QwtAbstractSlider::sliderChange
virtual void sliderChange()
Calling update()
Definition: qwt_abstract_slider.cpp:829
QwtAbstractSlider::singleSteps
uint singleSteps() const
Definition: qwt_abstract_slider.cpp:508
QwtAbstractSlider::keyPressEvent
virtual void keyPressEvent(QKeyEvent *) override
Definition: qwt_abstract_slider.cpp:370
QwtAbstractSlider::setTracking
void setTracking(bool)
Enables or disables tracking.
Definition: qwt_abstract_slider.cpp:177
QwtAbstractSlider::mousePressEvent
virtual void mousePressEvent(QMouseEvent *) override
Definition: qwt_abstract_slider.cpp:195
QwtAbstractSlider::setTotalSteps
void setTotalSteps(uint)
Set the number of steps.
Definition: qwt_abstract_slider.cpp:474
QwtAbstractSlider::setValid
void setValid(bool)
Definition: qwt_abstract_slider.cpp:113
QwtAbstractSlider::valueChanged
void valueChanged(double value)
Notify a change of value.
QwtAbstractSlider::setValue
void setValue(double value)
Definition: qwt_abstract_slider.cpp:570
QwtAbstractSlider::wrapping
bool wrapping() const
Definition: qwt_abstract_slider.cpp:608
QwtAbstractSlider::incrementedValue
double incrementedValue(double value, int stepCount) const
Definition: qwt_abstract_slider.cpp:670
QwtAbstractSlider::isTracking
bool isTracking() const
Definition: qwt_abstract_slider.cpp:186
QwtAbstractSlider::setStepAlignment
void setStepAlignment(bool)
Enable step alignment.
Definition: qwt_abstract_slider.cpp:547
QwtAbstractSlider::isReadOnly
bool isReadOnly() const
Definition: qwt_abstract_slider.cpp:159
QwtAbstractSlider::setInvertedControls
void setInvertedControls(bool)
Definition: qwt_abstract_slider.cpp:628
QwtAbstractSlider::incrementValue
void incrementValue(int stepCount)
Definition: qwt_abstract_slider.cpp:650
QwtAbstractSlider::totalSteps
uint totalSteps() const
Definition: qwt_abstract_slider.cpp:483
QwtAbstractSlider::stepAlignment
bool stepAlignment() const
Definition: qwt_abstract_slider.cpp:559
QwtAbstractSlider::setReadOnly
void setReadOnly(bool)
Definition: qwt_abstract_slider.cpp:141
QwtAbstractSlider::isValid
bool isValid() const
Definition: qwt_abstract_slider.cpp:125
QwtAbstractSlider::mouseMoveEvent
virtual void mouseMoveEvent(QMouseEvent *) override
Definition: qwt_abstract_slider.cpp:220
QwtAbstractSlider::sliderReleased
void sliderReleased()
QwtAbstractSlider::wheelEvent
virtual void wheelEvent(QWheelEvent *) override
Definition: qwt_abstract_slider.cpp:296
QwtAbstractSlider::setSingleSteps
void setSingleSteps(uint)
Set the number of steps for a single increment.
Definition: qwt_abstract_slider.cpp:499
QwtAbstractSlider::value
double value() const
Returns the current value.
Definition: qwt_abstract_slider.cpp:587
QwtAbstractSlider::setWrapping
void setWrapping(bool)
Definition: qwt_abstract_slider.cpp:599
QwtAbstractSlider::pageSteps
uint pageSteps() const
Definition: qwt_abstract_slider.cpp:533
QwtAbstractSlider::setPageSteps
void setPageSteps(uint)
Set the number of steps for a page increment.
Definition: qwt_abstract_slider.cpp:524
QwtAbstractSlider::sliderMoved
void sliderMoved(double value)
QwtAbstractSlider::isScrollPosition
virtual bool isScrollPosition(const QPoint &pos) const =0
Determine what to do when the user presses a mouse button.
QwtAbstractSlider::scrolledTo
virtual double scrolledTo(const QPoint &pos) const =0
Determine the value for a new position of the movable part of the slider.
QwtAbstractSlider::QwtAbstractSlider
QwtAbstractSlider(QWidget *parent=NULL)
Constructor.
Definition: qwt_abstract_slider.cpp:91
QwtAbstractSlider::sliderPressed
void sliderPressed()
QwtScaleDiv
A class representing a scale division.
Definition: qwt_scale_div.h:34
QwtScaleDiv::lowerBound
double lowerBound() const
Definition: qwt_scale_div.cpp:131
QwtScaleDiv::upperBound
double upperBound() const
Definition: qwt_scale_div.cpp:151
QwtScaleDiv::ticks
QList< double > ticks(int tickType) const
Definition: qwt_scale_div.cpp:309
QwtScaleDiv::NTickTypes
@ NTickTypes
Number of valid tick types.
Definition: qwt_scale_div.h:52
QwtScaleMap
A scale map.
Definition: qwt_scale_map.h:27
QwtScaleMap::p1
double p1() const
Definition: qwt_scale_map.h:99
QwtScaleMap::transform
double transform(double s) const
Definition: qwt_scale_map.h:137
QwtScaleMap::transformation
const QwtTransform * transformation() const
Get the transformation.
Definition: qwt_scale_map.cpp:88
QwtScaleMap::setPaintInterval
void setPaintInterval(double p1, double p2)
Specify the borders of the paint device interval.
Definition: qwt_scale_map.cpp:119
QwtScaleMap::invTransform
double invTransform(double p) const
Definition: qwt_scale_map.h:154
QwtScaleMap::p2
double p2() const
Definition: qwt_scale_map.h:107
QwtTransform
A transformation between coordinate systems.
Definition: qwt_transform.h:36
QwtTransform::transform
virtual double transform(double value) const =0
QwtTransform::invTransform
virtual double invTransform(double value) const =0