source: ntrip/trunk/BNC/qwt/qwt_wheel.cpp@ 8418

Last change on this file since 8418 was 8127, checked in by stoecker, 8 years ago

update qwt and qwtpolar, many QT5 fixes (unfinished)

File size: 29.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_wheel.h"
11#include "qwt_math.h"
12#include "qwt_painter.h"
13#include <qevent.h>
14#include <qdrawutil.h>
15#include <qpainter.h>
16#include <qstyle.h>
17#include <qstyleoption.h>
18#include <qapplication.h>
19#include <qdatetime.h>
20
21#if QT_VERSION < 0x040601
22#define qFabs(x) ::fabs(x)
23#define qFastSin(x) ::sin(x)
24#define qExp(x) ::exp(x)
25#endif
26
27class QwtWheel::PrivateData
28{
29public:
30 PrivateData():
31 orientation( Qt::Horizontal ),
32 viewAngle( 175.0 ),
33 totalAngle( 360.0 ),
34 tickCount( 10 ),
35 wheelBorderWidth( 2 ),
36 borderWidth( 2 ),
37 wheelWidth( 20 ),
38 isScrolling( false ),
39 mouseOffset( 0.0 ),
40 tracking( true ),
41 pendingValueChanged( false ),
42 updateInterval( 50 ),
43 mass( 0.0 ),
44 timerId( 0 ),
45 speed( 0.0 ),
46 mouseValue( 0.0 ),
47 flyingValue( 0.0 ),
48 minimum( 0.0 ),
49 maximum( 100.0 ),
50 singleStep( 1.0 ),
51 pageStepCount( 1 ),
52 stepAlignment( true ),
53 value( 0.0 ),
54 inverted( false ),
55 wrapping( false )
56 {
57 };
58
59 Qt::Orientation orientation;
60 double viewAngle;
61 double totalAngle;
62 int tickCount;
63 int wheelBorderWidth;
64 int borderWidth;
65 int wheelWidth;
66
67 bool isScrolling;
68 double mouseOffset;
69
70 bool tracking;
71 bool pendingValueChanged; // when not tracking
72
73 int updateInterval;
74 double mass;
75
76 // for the flying wheel effect
77 int timerId;
78 QTime time;
79 double speed;
80 double mouseValue;
81 double flyingValue;
82
83 double minimum;
84 double maximum;
85
86 double singleStep;
87 int pageStepCount;
88 bool stepAlignment;
89
90 double value;
91
92 bool inverted;
93 bool wrapping;
94};
95
96//! Constructor
97QwtWheel::QwtWheel( QWidget *parent ):
98 QWidget( parent )
99{
100 d_data = new PrivateData;
101
102 setFocusPolicy( Qt::StrongFocus );
103 setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
104 setAttribute( Qt::WA_WState_OwnSizePolicy, false );
105}
106
107//! Destructor
108QwtWheel::~QwtWheel()
109{
110 delete d_data;
111}
112
113/*!
114 \brief En/Disable tracking
115
116 If tracking is enabled (the default), the wheel emits the valueChanged()
117 signal while the wheel is moving. If tracking is disabled, the wheel
118 emits the valueChanged() signal only when the wheel movement is terminated.
119
120 The wheelMoved() signal is emitted regardless id tracking is enabled or not.
121
122 \param enable On/Off
123 \sa isTracking()
124 */
125void QwtWheel::setTracking( bool enable )
126{
127 d_data->tracking = enable;
128}
129
130/*!
131 \return True, when tracking is enabled
132 \sa setTracking(), valueChanged(), wheelMoved()
133*/
134bool QwtWheel::isTracking() const
135{
136 return d_data->tracking;
137}
138
139/*!
140 \brief Specify the update interval when the wheel is flying
141
142 Default and minimum value is 50 ms.
143
144 \param interval Interval in milliseconds
145 \sa updateInterval(), setMass(), setTracking()
146*/
147void QwtWheel::setUpdateInterval( int interval )
148{
149 d_data->updateInterval = qMax( interval, 50 );
150}
151
152/*!
153 \return Update interval when the wheel is flying
154 \sa setUpdateInterval(), mass(), isTracking()
155 */
156int QwtWheel::updateInterval() const
157{
158 return d_data->updateInterval;
159}
160
161/*!
162 \brief Mouse press event handler
163
164 Start movement of the wheel.
165
166 \param event Mouse event
167*/
168void QwtWheel::mousePressEvent( QMouseEvent *event )
169{
170 stopFlying();
171
172 d_data->isScrolling = wheelRect().contains( event->pos() );
173
174 if ( d_data->isScrolling )
175 {
176 d_data->time.start();
177 d_data->speed = 0.0;
178 d_data->mouseValue = valueAt( event->pos() );
179 d_data->mouseOffset = d_data->mouseValue - d_data->value;
180 d_data->pendingValueChanged = false;
181
182 Q_EMIT wheelPressed();
183 }
184}
185
186/*!
187 \brief Mouse Move Event handler
188
189 Turn the wheel according to the mouse position
190
191 \param event Mouse event
192*/
193void QwtWheel::mouseMoveEvent( QMouseEvent *event )
194{
195 if ( !d_data->isScrolling )
196 return;
197
198 double mouseValue = valueAt( event->pos() );
199
200 if ( d_data->mass > 0.0 )
201 {
202 double ms = d_data->time.restart();
203
204 // the interval when mouse move events are posted are somehow
205 // random. To avoid unrealistic speed values we limit ms
206
207 ms = qMax( ms, 5.0 );
208
209 d_data->speed = ( mouseValue - d_data->mouseValue ) / ms;
210 }
211
212 d_data->mouseValue = mouseValue;
213
214 double value = boundedValue( mouseValue - d_data->mouseOffset );
215 if ( d_data->stepAlignment )
216 value = alignedValue( value );
217
218 if ( value != d_data->value )
219 {
220 d_data->value = value;
221
222 update();
223
224 Q_EMIT wheelMoved( d_data->value );
225
226 if ( d_data->tracking )
227 Q_EMIT valueChanged( d_data->value );
228 else
229 d_data->pendingValueChanged = true;
230 }
231}
232
233/*!
234 \brief Mouse Release Event handler
235
236 When the wheel has no mass the movement of the wheel stops, otherwise
237 it starts flying.
238
239 \param event Mouse event
240*/
241
242void QwtWheel::mouseReleaseEvent( QMouseEvent *event )
243{
244 Q_UNUSED( event );
245
246 if ( !d_data->isScrolling )
247 return;
248
249 d_data->isScrolling = false;
250
251 bool startFlying = false;
252
253 if ( d_data->mass > 0.0 )
254 {
255 const int ms = d_data->time.elapsed();
256 if ( ( qFabs( d_data->speed ) > 0.0 ) && ( ms < 50 ) )
257 startFlying = true;
258 }
259
260 if ( startFlying )
261 {
262 d_data->flyingValue =
263 boundedValue( d_data->mouseValue - d_data->mouseOffset );
264
265 d_data->timerId = startTimer( d_data->updateInterval );
266 }
267 else
268 {
269 if ( d_data->pendingValueChanged )
270 Q_EMIT valueChanged( d_data->value );
271 }
272
273 d_data->pendingValueChanged = false;
274 d_data->mouseOffset = 0.0;
275
276 Q_EMIT wheelReleased();
277}
278
279/*!
280 \brief Qt timer event
281
282 The flying wheel effect is implemented using a timer
283
284 \param event Timer event
285
286 \sa updateInterval()
287 */
288void QwtWheel::timerEvent( QTimerEvent *event )
289{
290 if ( event->timerId() != d_data->timerId )
291 {
292 QWidget::timerEvent( event );
293 return;
294 }
295
296 d_data->speed *= qExp( -d_data->updateInterval * 0.001 / d_data->mass );
297
298 d_data->flyingValue += d_data->speed * d_data->updateInterval;
299 d_data->flyingValue = boundedValue( d_data->flyingValue );
300
301 double value = d_data->flyingValue;
302 if ( d_data->stepAlignment )
303 value = alignedValue( value );
304
305 if ( qFabs( d_data->speed ) < 0.001 * d_data->singleStep )
306 {
307 // stop if d_data->speed < one step per second
308 stopFlying();
309 }
310
311 if ( value != d_data->value )
312 {
313 d_data->value = value;
314 update();
315
316 if ( d_data->tracking || d_data->timerId == 0 )
317 Q_EMIT valueChanged( d_data->value );
318 }
319}
320
321
322/*!
323 \brief Handle wheel events
324
325 In/Decrement the value
326
327 \param event Wheel event
328*/
329void QwtWheel::wheelEvent( QWheelEvent *event )
330{
331 if ( !wheelRect().contains( event->pos() ) )
332 {
333 event->ignore();
334 return;
335 }
336
337 if ( d_data->isScrolling )
338 return;
339
340 stopFlying();
341
342 double increment = 0.0;
343
344 if ( ( event->modifiers() & Qt::ControlModifier) ||
345 ( event->modifiers() & Qt::ShiftModifier ) )
346 {
347 // one page regardless of delta
348 increment = d_data->singleStep * d_data->pageStepCount;
349 if ( event->delta() < 0 )
350 increment = -increment;
351 }
352 else
353 {
354 const int numSteps = event->delta() / 120;
355 increment = d_data->singleStep * numSteps;
356 }
357
358 if ( d_data->orientation == Qt::Vertical && d_data->inverted )
359 increment = -increment;
360
361 double value = boundedValue( d_data->value + increment );
362
363 if ( d_data->stepAlignment )
364 value = alignedValue( value );
365
366 if ( value != d_data->value )
367 {
368 d_data->value = value;
369 update();
370
371 Q_EMIT valueChanged( d_data->value );
372 Q_EMIT wheelMoved( d_data->value );
373 }
374}
375
376/*!
377 Handle key events
378
379 - Qt::Key_Home\n
380 Step to minimum()
381
382 - Qt::Key_End\n
383 Step to maximum()
384
385 - Qt::Key_Up\n
386 In case of a horizontal or not inverted vertical wheel the value
387 will be incremented by the step size. For an inverted vertical wheel
388 the value will be decremented by the step size.
389
390 - Qt::Key_Down\n
391 In case of a horizontal or not inverted vertical wheel the value
392 will be decremented by the step size. For an inverted vertical wheel
393 the value will be incremented by the step size.
394
395 - Qt::Key_PageUp\n
396 The value will be incremented by pageStepSize() * singleStepSize().
397
398 - Qt::Key_PageDown\n
399 The value will be decremented by pageStepSize() * singleStepSize().
400
401 \param event Key event
402*/
403void QwtWheel::keyPressEvent( QKeyEvent *event )
404{
405 if ( d_data->isScrolling )
406 {
407 // don't interfere mouse scrolling
408 return;
409 }
410
411 double value = d_data->value;
412 double increment = 0.0;
413
414 switch ( event->key() )
415 {
416 case Qt::Key_Down:
417 {
418 if ( d_data->orientation == Qt::Vertical && d_data->inverted )
419 increment = d_data->singleStep;
420 else
421 increment = -d_data->singleStep;
422
423 break;
424 }
425 case Qt::Key_Up:
426 {
427 if ( d_data->orientation == Qt::Vertical && d_data->inverted )
428 increment = -d_data->singleStep;
429 else
430 increment = d_data->singleStep;
431
432 break;
433 }
434 case Qt::Key_Left:
435 {
436 if ( d_data->orientation == Qt::Horizontal )
437 {
438 if ( d_data->inverted )
439 increment = d_data->singleStep;
440 else
441 increment = -d_data->singleStep;
442 }
443 break;
444 }
445 case Qt::Key_Right:
446 {
447 if ( d_data->orientation == Qt::Horizontal )
448 {
449 if ( d_data->inverted )
450 increment = -d_data->singleStep;
451 else
452 increment = d_data->singleStep;
453 }
454 break;
455 }
456 case Qt::Key_PageUp:
457 {
458 increment = d_data->pageStepCount * d_data->singleStep;
459 break;
460 }
461 case Qt::Key_PageDown:
462 {
463 increment = -d_data->pageStepCount * d_data->singleStep;
464 break;
465 }
466 case Qt::Key_Home:
467 {
468 value = d_data->minimum;
469 break;
470 }
471 case Qt::Key_End:
472 {
473 value = d_data->maximum;
474 break;
475 }
476 default:;
477 {
478 event->ignore();
479 }
480 }
481
482 if ( event->isAccepted() )
483 stopFlying();
484
485 if ( increment != 0.0 )
486 {
487 value = boundedValue( d_data->value + increment );
488
489 if ( d_data->stepAlignment )
490 value = alignedValue( value );
491 }
492
493 if ( value != d_data->value )
494 {
495 d_data->value = value;
496 update();
497
498 Q_EMIT valueChanged( d_data->value );
499 Q_EMIT wheelMoved( d_data->value );
500 }
501}
502
503/*!
504 \brief Adjust the number of grooves in the wheel's surface.
505
506 The number of grooves is limited to 6 <= count <= 50.
507 Values outside this range will be clipped.
508 The default value is 10.
509
510 \param count Number of grooves per 360 degrees
511 \sa tickCount()
512*/
513void QwtWheel::setTickCount( int count )
514{
515 count = qBound( 6, count, 50 );
516
517 if ( count != d_data->tickCount )
518 {
519 d_data->tickCount = qBound( 6, count, 50 );
520 update();
521 }
522}
523
524/*!
525 \return Number of grooves in the wheel's surface.
526 \sa setTickCnt()
527*/
528int QwtWheel::tickCount() const
529{
530 return d_data->tickCount;
531}
532
533/*!
534 \brief Set the wheel border width of the wheel.
535
536 The wheel border must not be smaller than 1
537 and is limited in dependence on the wheel's size.
538 Values outside the allowed range will be clipped.
539
540 The wheel border defaults to 2.
541
542 \param borderWidth Border width
543 \sa internalBorder()
544*/
545void QwtWheel::setWheelBorderWidth( int borderWidth )
546{
547 const int d = qMin( width(), height() ) / 3;
548 borderWidth = qMin( borderWidth, d );
549 d_data->wheelBorderWidth = qMax( borderWidth, 1 );
550 update();
551}
552
553/*!
554 \return Wheel border width
555 \sa setWheelBorderWidth()
556*/
557int QwtWheel::wheelBorderWidth() const
558{
559 return d_data->wheelBorderWidth;
560}
561
562/*!
563 \brief Set the border width
564
565 The border defaults to 2.
566
567 \param width Border width
568 \sa borderWidth()
569*/
570void QwtWheel::setBorderWidth( int width )
571{
572 d_data->borderWidth = qMax( width, 0 );
573 update();
574}
575
576/*!
577 \return Border width
578 \sa setBorderWidth()
579*/
580int QwtWheel::borderWidth() const
581{
582 return d_data->borderWidth;
583}
584
585/*!
586 \return Rectangle of the wheel without the outer border
587*/
588QRect QwtWheel::wheelRect() const
589{
590 const int bw = d_data->borderWidth;
591 return contentsRect().adjusted( bw, bw, -bw, -bw );
592}
593
594/*!
595 \brief Set the total angle which the wheel can be turned.
596
597 One full turn of the wheel corresponds to an angle of
598 360 degrees. A total angle of n*360 degrees means
599 that the wheel has to be turned n times around its axis
600 to get from the minimum value to the maximum value.
601
602 The default setting of the total angle is 360 degrees.
603
604 \param angle total angle in degrees
605 \sa totalAngle()
606*/
607void QwtWheel::setTotalAngle( double angle )
608{
609 if ( angle < 0.0 )
610 angle = 0.0;
611
612 d_data->totalAngle = angle;
613 update();
614}
615
616/*!
617 \return Total angle which the wheel can be turned.
618 \sa setTotalAngle()
619*/
620double QwtWheel::totalAngle() const
621{
622 return d_data->totalAngle;
623}
624
625/*!
626 \brief Set the wheel's orientation.
627
628 The default orientation is Qt::Horizontal.
629
630 \param orientation Qt::Horizontal or Qt::Vertical.
631 \sa orientation()
632*/
633void QwtWheel::setOrientation( Qt::Orientation orientation )
634{
635 if ( d_data->orientation == orientation )
636 return;
637
638 if ( !testAttribute( Qt::WA_WState_OwnSizePolicy ) )
639 {
640 QSizePolicy sp = sizePolicy();
641 sp.transpose();
642 setSizePolicy( sp );
643
644 setAttribute( Qt::WA_WState_OwnSizePolicy, false );
645 }
646
647 d_data->orientation = orientation;
648 update();
649}
650
651/*!
652 \return Orientation
653 \sa setOrientation()
654*/
655Qt::Orientation QwtWheel::orientation() const
656{
657 return d_data->orientation;
658}
659
660/*!
661 \brief Specify the visible portion of the wheel.
662
663 You may use this function for fine-tuning the appearance of
664 the wheel. The default value is 175 degrees. The value is
665 limited from 10 to 175 degrees.
666
667 \param angle Visible angle in degrees
668 \sa viewAngle(), setTotalAngle()
669*/
670void QwtWheel::setViewAngle( double angle )
671{
672 d_data->viewAngle = qBound( 10.0, angle, 175.0 );
673 update();
674}
675
676/*!
677 \return Visible portion of the wheel
678 \sa setViewAngle(), totalAngle()
679*/
680double QwtWheel::viewAngle() const
681{
682 return d_data->viewAngle;
683}
684
685/*!
686 Determine the value corresponding to a specified point
687
688 \param pos Position
689 \return Value corresponding to pos
690*/
691double QwtWheel::valueAt( const QPoint &pos ) const
692{
693 const QRectF rect = wheelRect();
694
695 double w, dx;
696 if ( d_data->orientation == Qt::Vertical )
697 {
698 w = rect.height();
699 dx = rect.top() - pos.y();
700 }
701 else
702 {
703 w = rect.width();
704 dx = pos.x() - rect.left();
705 }
706
707 if ( w == 0.0 )
708 return 0.0;
709
710 if ( d_data->inverted )
711 {
712 dx = w - dx;
713 }
714
715 // w pixels is an arc of viewAngle degrees,
716 // so we convert change in pixels to change in angle
717 const double ang = dx * d_data->viewAngle / w;
718
719 // value range maps to totalAngle degrees,
720 // so convert the change in angle to a change in value
721 const double val = ang * ( maximum() - minimum() ) / d_data->totalAngle;
722
723 return val;
724}
725
726/*!
727 \brief Qt Paint Event
728 \param event Paint event
729*/
730void QwtWheel::paintEvent( QPaintEvent *event )
731{
732 QPainter painter( this );
733 painter.setClipRegion( event->region() );
734
735 QStyleOption opt;
736 opt.init(this);
737 style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
738
739 qDrawShadePanel( &painter,
740 contentsRect(), palette(), true, d_data->borderWidth );
741
742 drawWheelBackground( &painter, wheelRect() );
743 drawTicks( &painter, wheelRect() );
744
745 if ( hasFocus() )
746 QwtPainter::drawFocusRect( &painter, this );
747}
748
749/*!
750 Draw the Wheel's background gradient
751
752 \param painter Painter
753 \param rect Geometry for the wheel
754*/
755void QwtWheel::drawWheelBackground(
756 QPainter *painter, const QRectF &rect )
757{
758 painter->save();
759
760 QPalette pal = palette();
761
762 // draw shaded background
763 QLinearGradient gradient( rect.topLeft(),
764 ( d_data->orientation == Qt::Horizontal ) ? rect.topRight() : rect.bottomLeft() );
765 gradient.setColorAt( 0.0, pal.color( QPalette::Button ) );
766 gradient.setColorAt( 0.2, pal.color( QPalette::Midlight ) );
767 gradient.setColorAt( 0.7, pal.color( QPalette::Mid ) );
768 gradient.setColorAt( 1.0, pal.color( QPalette::Dark ) );
769
770 painter->fillRect( rect, gradient );
771
772 // draw internal border
773
774 const QPen lightPen( palette().color( QPalette::Light ),
775 d_data->wheelBorderWidth, Qt::SolidLine, Qt::FlatCap );
776 const QPen darkPen( pal.color( QPalette::Dark ),
777 d_data->wheelBorderWidth, Qt::SolidLine, Qt::FlatCap );
778
779 const double bw2 = 0.5 * d_data->wheelBorderWidth;
780
781 if ( d_data->orientation == Qt::Horizontal )
782 {
783 painter->setPen( lightPen );
784 painter->drawLine( QPointF( rect.left(), rect.top() + bw2 ),
785 QPointF( rect.right(), rect.top() + bw2 ) );
786
787 painter->setPen( darkPen );
788 painter->drawLine( QPointF( rect.left(), rect.bottom() - bw2 ),
789 QPointF( rect.right(), rect.bottom() - bw2 ) );
790 }
791 else // Qt::Vertical
792 {
793 painter->setPen( lightPen );
794 painter->drawLine( QPointF( rect.left() + bw2, rect.top() ),
795 QPointF( rect.left() + bw2, rect.bottom() ) );
796
797 painter->setPen( darkPen );
798 painter->drawLine( QPointF( rect.right() - bw2, rect.top() ),
799 QPointF( rect.right() - bw2, rect.bottom() ) );
800 }
801
802 painter->restore();
803}
804
805/*!
806 Draw the Wheel's ticks
807
808 \param painter Painter
809 \param rect Geometry for the wheel
810*/
811void QwtWheel::drawTicks( QPainter *painter, const QRectF &rect )
812{
813 const double range = d_data->maximum - d_data->minimum;
814
815 if ( range == 0.0 || d_data->totalAngle == 0.0 )
816 {
817 return;
818 }
819
820 const QPen lightPen( palette().color( QPalette::Light ),
821 0, Qt::SolidLine, Qt::FlatCap );
822 const QPen darkPen( palette().color( QPalette::Dark ),
823 0, Qt::SolidLine, Qt::FlatCap );
824
825 const double cnvFactor = qAbs( d_data->totalAngle / range );
826 const double halfIntv = 0.5 * d_data->viewAngle / cnvFactor;
827 const double loValue = value() - halfIntv;
828 const double hiValue = value() + halfIntv;
829 const double tickWidth = 360.0 / double( d_data->tickCount ) / cnvFactor;
830 const double sinArc = qFastSin( d_data->viewAngle * M_PI / 360.0 );
831
832 if ( d_data->orientation == Qt::Horizontal )
833 {
834 const double radius = rect.width() * 0.5;
835
836 double l1 = rect.top() + d_data->wheelBorderWidth;
837 double l2 = rect.bottom() - d_data->wheelBorderWidth - 1;
838
839 // draw one point over the border if border > 1
840 if ( d_data->wheelBorderWidth > 1 )
841 {
842 l1--;
843 l2++;
844 }
845
846 const double maxpos = rect.right() - 2;
847 const double minpos = rect.left() + 2;
848
849 // draw tick marks
850 for ( double tickValue = ::ceil( loValue / tickWidth ) * tickWidth;
851 tickValue < hiValue; tickValue += tickWidth )
852 {
853 const double angle = qwtRadians( tickValue - value() );
854 const double s = qFastSin( angle * cnvFactor );
855
856 const double off = radius * ( sinArc + s ) / sinArc;
857
858 double tickPos;
859 if ( d_data->inverted )
860 tickPos = rect.left() + off;
861 else
862 tickPos = rect.right() - off;
863
864 if ( ( tickPos <= maxpos ) && ( tickPos > minpos ) )
865 {
866 painter->setPen( darkPen );
867 painter->drawLine( QPointF( tickPos - 1 , l1 ),
868 QPointF( tickPos - 1, l2 ) );
869 painter->setPen( lightPen );
870 painter->drawLine( QPointF( tickPos, l1 ),
871 QPointF( tickPos, l2 ) );
872 }
873 }
874 }
875 else // Qt::Vertical
876 {
877 const double radius = rect.height() * 0.5;
878
879 double l1 = rect.left() + d_data->wheelBorderWidth;
880 double l2 = rect.right() - d_data->wheelBorderWidth - 1;
881
882 if ( d_data->wheelBorderWidth > 1 )
883 {
884 l1--;
885 l2++;
886 }
887
888 const double maxpos = rect.bottom() - 2;
889 const double minpos = rect.top() + 2;
890
891 for ( double tickValue = ::ceil( loValue / tickWidth ) * tickWidth;
892 tickValue < hiValue; tickValue += tickWidth )
893 {
894 const double angle = qwtRadians( tickValue - value() );
895 const double s = qFastSin( angle * cnvFactor );
896
897 const double off = radius * ( sinArc + s ) / sinArc;
898
899 double tickPos;
900
901 if ( d_data->inverted )
902 tickPos = rect.bottom() - off;
903 else
904 tickPos = rect.top() + off;
905
906 if ( ( tickPos <= maxpos ) && ( tickPos > minpos ) )
907 {
908 painter->setPen( darkPen );
909 painter->drawLine( QPointF( l1, tickPos - 1 ),
910 QPointF( l2, tickPos - 1 ) );
911 painter->setPen( lightPen );
912 painter->drawLine( QPointF( l1, tickPos ),
913 QPointF( l2, tickPos ) );
914 }
915 }
916 }
917}
918
919/*!
920 \brief Set the width of the wheel
921
922 Corresponds to the wheel height for horizontal orientation,
923 and the wheel width for vertical orientation.
924
925 \param width the wheel's width
926 \sa wheelWidth()
927*/
928void QwtWheel::setWheelWidth( int width )
929{
930 d_data->wheelWidth = width;
931 update();
932}
933
934/*!
935 \return Width of the wheel
936 \sa setWheelWidth()
937*/
938int QwtWheel::wheelWidth() const
939{
940 return d_data->wheelWidth;
941}
942
943/*!
944 \return a size hint
945*/
946QSize QwtWheel::sizeHint() const
947{
948 const QSize hint = minimumSizeHint();
949 return hint.expandedTo( QApplication::globalStrut() );
950}
951
952/*!
953 \return Minimum size hint
954 \warning The return value is based on the wheel width.
955*/
956QSize QwtWheel::minimumSizeHint() const
957{
958 QSize sz( 3 * d_data->wheelWidth + 2 * d_data->borderWidth,
959 d_data->wheelWidth + 2 * d_data->borderWidth );
960 if ( d_data->orientation != Qt::Horizontal )
961 sz.transpose();
962
963 return sz;
964}
965
966/*!
967 \brief Set the step size of the counter
968
969 A value <= 0.0 disables stepping
970
971 \param stepSize Single step size
972 \sa singleStep(), setPageStepCount()
973*/
974void QwtWheel::setSingleStep( double stepSize )
975{
976 d_data->singleStep = qMax( stepSize, 0.0 );
977}
978
979/*!
980 \return Single step size
981 \sa setSingleStep()
982 */
983double QwtWheel::singleStep() const
984{
985 return d_data->singleStep;
986}
987
988/*!
989 \brief En/Disable step alignment
990
991 When step alignment is enabled value changes initiated by
992 user input ( mouse, keyboard, wheel ) are aligned to
993 the multiples of the single step.
994
995 \param on On/Off
996 \sa stepAlignment(), setSingleStep()
997 */
998void QwtWheel::setStepAlignment( bool on )
999{
1000 if ( on != d_data->stepAlignment )
1001 {
1002 d_data->stepAlignment = on;
1003 }
1004}
1005
1006/*!
1007 \return True, when the step alignment is enabled
1008 \sa setStepAlignment(), singleStep()
1009 */
1010bool QwtWheel::stepAlignment() const
1011{
1012 return d_data->stepAlignment;
1013}
1014
1015/*!
1016 \brief Set the page step count
1017
1018 pageStepCount is a multiplicator for the single step size
1019 that typically corresponds to the user pressing PageUp or PageDown.
1020
1021 A value of 0 disables page stepping.
1022
1023 The default value is 1.
1024
1025 \param count Multiplicator for the single step size
1026 \sa pageStepCount(), setSingleStep()
1027 */
1028void QwtWheel::setPageStepCount( int count )
1029{
1030 d_data->pageStepCount = qMax( 0, count );
1031}
1032
1033/*!
1034 \return Page step count
1035 \sa setPageStepCount(), singleStep()
1036 */
1037int QwtWheel::pageStepCount() const
1038{
1039 return d_data->pageStepCount;
1040}
1041
1042/*!
1043 \brief Set the minimum and maximum values
1044
1045 The maximum is adjusted if necessary to ensure that the range remains valid.
1046 The value might be modified to be inside of the range.
1047
1048 \param min Minimum value
1049 \param max Maximum value
1050
1051 \sa minimum(), maximum()
1052 */
1053void QwtWheel::setRange( double min, double max )
1054{
1055 max = qMax( min, max );
1056
1057 if ( d_data->minimum == min && d_data->maximum == max )
1058 return;
1059
1060 d_data->minimum = min;
1061 d_data->maximum = max;
1062
1063 if ( d_data->value < min || d_data->value > max )
1064 {
1065 d_data->value = qBound( min, d_data->value, max );
1066
1067 update();
1068 Q_EMIT valueChanged( d_data->value );
1069 }
1070}
1071/*!
1072 Set the minimum value of the range
1073
1074 \param value Minimum value
1075 \sa setRange(), setMaximum(), minimum()
1076
1077 \note The maximum is adjusted if necessary to ensure that the range remains valid.
1078*/
1079void QwtWheel::setMinimum( double value )
1080{
1081 setRange( value, maximum() );
1082}
1083
1084/*!
1085 \return The minimum of the range
1086 \sa setRange(), setMinimum(), maximum()
1087*/
1088double QwtWheel::minimum() const
1089{
1090 return d_data->minimum;
1091}
1092
1093/*!
1094 Set the maximum value of the range
1095
1096 \param value Maximum value
1097 \sa setRange(), setMinimum(), maximum()
1098*/
1099void QwtWheel::setMaximum( double value )
1100{
1101 setRange( minimum(), value );
1102}
1103
1104/*!
1105 \return The maximum of the range
1106 \sa setRange(), setMaximum(), minimum()
1107*/
1108double QwtWheel::maximum() const
1109{
1110 return d_data->maximum;
1111}
1112
1113/*!
1114 \brief Set a new value without adjusting to the step raster
1115
1116 \param value New value
1117
1118 \sa value(), valueChanged()
1119 \warning The value is clipped when it lies outside the range.
1120*/
1121void QwtWheel::setValue( double value )
1122{
1123 stopFlying();
1124 d_data->isScrolling = false;
1125
1126 value = qBound( d_data->minimum, value, d_data->maximum );
1127
1128 if ( d_data->value != value )
1129 {
1130 d_data->value = value;
1131
1132 update();
1133 Q_EMIT valueChanged( d_data->value );
1134 }
1135}
1136
1137/*!
1138 \return Current value of the wheel
1139 \sa setValue(), valueChanged()
1140 */
1141double QwtWheel::value() const
1142{
1143 return d_data->value;
1144}
1145
1146/*!
1147 \brief En/Disable inverted appearance
1148
1149 An inverted wheel increases its values in the opposite direction.
1150 The direction of an inverted horizontal wheel will be from right to left
1151 an inverted vertical wheel will increase from bottom to top.
1152
1153 \param on En/Disable inverted appearance
1154 \sa isInverted()
1155
1156 */
1157void QwtWheel::setInverted( bool on )
1158{
1159 if ( d_data->inverted != on )
1160 {
1161 d_data->inverted = on;
1162 update();
1163 }
1164}
1165
1166/*!
1167 \return True, when the wheel is inverted
1168 \sa setInverted()
1169 */
1170bool QwtWheel::isInverted() const
1171{
1172 return d_data->inverted;
1173}
1174
1175/*!
1176 \brief En/Disable wrapping
1177
1178 If wrapping is true stepping up from maximum() value will take
1179 you to the minimum() value and vice versa.
1180
1181 \param on En/Disable wrapping
1182 \sa wrapping()
1183 */
1184void QwtWheel::setWrapping( bool on )
1185{
1186 d_data->wrapping = on;
1187}
1188
1189/*!
1190 \return True, when wrapping is set
1191 \sa setWrapping()
1192 */
1193bool QwtWheel::wrapping() const
1194{
1195 return d_data->wrapping;
1196}
1197
1198/*!
1199 \brief Set the slider's mass for flywheel effect.
1200
1201 If the slider's mass is greater then 0, it will continue
1202 to move after the mouse button has been released. Its speed
1203 decreases with time at a rate depending on the slider's mass.
1204 A large mass means that it will continue to move for a
1205 long time.
1206
1207 Derived widgets may overload this function to make it public.
1208
1209 \param mass New mass in kg
1210
1211 \bug If the mass is smaller than 1g, it is set to zero.
1212 The maximal mass is limited to 100kg.
1213 \sa mass()
1214*/
1215void QwtWheel::setMass( double mass )
1216{
1217 if ( mass < 0.001 )
1218 {
1219 d_data->mass = 0.0;
1220 }
1221 else
1222 {
1223 d_data->mass = qMin( 100.0, mass );
1224 }
1225
1226 if ( d_data->mass <= 0.0 )
1227 stopFlying();
1228}
1229
1230/*!
1231 \return mass
1232 \sa setMass()
1233*/
1234double QwtWheel::mass() const
1235{
1236 return d_data->mass;
1237}
1238
1239//! Stop the flying movement of the wheel
1240void QwtWheel::stopFlying()
1241{
1242 if ( d_data->timerId != 0 )
1243 {
1244 killTimer( d_data->timerId );
1245 d_data->timerId = 0;
1246 d_data->speed = 0.0;
1247 }
1248}
1249
1250double QwtWheel::boundedValue( double value ) const
1251{
1252 const double range = d_data->maximum - d_data->minimum;
1253
1254 if ( d_data->wrapping && range >= 0.0 )
1255 {
1256 if ( value < d_data->minimum )
1257 {
1258 value += ::ceil( ( d_data->minimum - value ) / range ) * range;
1259 }
1260 else if ( value > d_data->maximum )
1261 {
1262 value -= ::ceil( ( value - d_data->maximum ) / range ) * range;
1263 }
1264 }
1265 else
1266 {
1267 value = qBound( d_data->minimum, value, d_data->maximum );
1268 }
1269
1270 return value;
1271}
1272
1273double QwtWheel::alignedValue( double value ) const
1274{
1275 const double stepSize = d_data->singleStep;
1276
1277 if ( stepSize > 0.0 )
1278 {
1279 value = d_data->minimum +
1280 qRound( ( value - d_data->minimum ) / stepSize ) * stepSize;
1281
1282 if ( stepSize > 1e-12 )
1283 {
1284 if ( qFuzzyCompare( value + 1.0, 1.0 ) )
1285 {
1286 // correct rounding error if value = 0
1287 value = 0.0;
1288 }
1289 else if ( qFuzzyCompare( value, d_data->maximum ) )
1290 {
1291 // correct rounding error at the border
1292 value = d_data->maximum;
1293 }
1294 }
1295 }
1296
1297 return value;
1298}
1299
Note: See TracBrowser for help on using the repository browser.