Qwt User's Guide 6.3.0
Loading...
Searching...
No Matches
qwt_dial.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_dial.h"
11#include "qwt_dial_needle.h"
12#include "qwt_math.h"
13#include "qwt_scale_map.h"
14#include "qwt_round_scale_draw.h"
15#include "qwt_painter.h"
16#include "qwt.h"
17
18#include <qpainter.h>
19#include <qpalette.h>
20#include <qpixmap.h>
21#include <qevent.h>
22#include <qstyle.h>
23#include <qstyleoption.h>
24
25static inline double qwtAngleDist( double a1, double a2 )
26{
27 double dist = qAbs( a2 - a1 );
28 if ( dist > 360.0 )
29 dist -= 360.0;
30
31 return dist;
32}
33
34static inline bool qwtIsOnArc( double angle, double min, double max )
35{
36 if ( min < max )
37 {
38 return ( angle >= min ) && ( angle <= max );
39 }
40 else
41 {
42 return ( angle >= min ) || ( angle <= max );
43 }
44}
45
46static inline double qwtBoundedAngle( double min, double angle, double max )
47{
48 double from = qwtNormalizeDegrees( min );
49 double to = qwtNormalizeDegrees( max );
50
51 double a;
52
53 if ( qwtIsOnArc( angle, from, to ) )
54 {
55 a = angle;
56 if ( a < min )
57 a += 360.0;
58 }
59 else
60 {
61 if ( qwtAngleDist( angle, from ) <
62 qwtAngleDist( angle, to ) )
63 {
64 a = min;
65 }
66 else
67 {
68 a = max;
69 }
70 }
71
72 return a;
73}
74
75class QwtDial::PrivateData
76{
77 public:
78 PrivateData()
79 : frameShadow( Sunken )
80 , lineWidth( 0 )
81 , mode( RotateNeedle )
82 , origin( 90.0 )
83 , minScaleArc( 0.0 )
84 , maxScaleArc( 0.0 )
85 , needle( NULL )
86 , arcOffset( 0.0 )
87 , mouseOffset( 0.0 )
88 {
89 }
90
91 ~PrivateData()
92 {
93 delete needle;
94 }
95 Shadow frameShadow;
96 int lineWidth;
97
98 QwtDial::Mode mode;
99
100 double origin;
101 double minScaleArc;
102 double maxScaleArc;
103
104 QwtDialNeedle* needle;
105
106 double arcOffset;
107 double mouseOffset;
108
109 QPixmap pixmapCache;
110};
111
124QwtDial::QwtDial( QWidget* parent )
125 : QwtAbstractSlider( parent )
126{
127 m_data = new PrivateData;
128
129 setFocusPolicy( Qt::TabFocus );
130
131 QPalette p = palette();
132 for ( int i = 0; i < QPalette::NColorGroups; i++ )
133 {
134 const QPalette::ColorGroup colorGroup =
135 static_cast< QPalette::ColorGroup >( i );
136
137 // Base: background color of the circle inside the frame.
138 // WindowText: background color of the circle inside the scale
139
140 p.setColor( colorGroup, QPalette::WindowText,
141 p.color( colorGroup, QPalette::Base ) );
142 }
143 setPalette( p );
144
146 scaleDraw->setRadius( 0 );
147
149
150 setScaleArc( 0.0, 360.0 ); // scale as a full circle
151
152 setScaleMaxMajor( 10 );
153 setScaleMaxMinor( 5 );
154
155 setValue( 0.0 );
156}
157
160{
161 delete m_data;
162}
163
171{
172 if ( shadow != m_data->frameShadow )
173 {
175
176 m_data->frameShadow = shadow;
177 if ( lineWidth() > 0 )
178 update();
179 }
180}
181
187{
188 return m_data->frameShadow;
189}
190
197void QwtDial::setLineWidth( int lineWidth )
198{
199 if ( lineWidth < 0 )
200 lineWidth = 0;
201
202 if ( m_data->lineWidth != lineWidth )
203 {
205
206 m_data->lineWidth = lineWidth;
207 update();
208 }
209}
210
216{
217 return m_data->lineWidth;
218}
219
225{
226 const int lw = lineWidth();
227 return boundingRect().adjusted( lw, lw, -lw, -lw );
228}
229
235{
236 const QRect cr = contentsRect();
237
238 const int dim = qMin( cr.width(), cr.height() );
239
240 QRect inner( 0, 0, dim, dim );
241 inner.moveCenter( cr.center() );
242
243 return inner;
244}
245
251{
252 QRect rect = innerRect();
253
254 const QwtAbstractScaleDraw* sd = scaleDraw();
255 if ( sd )
256 {
257 int scaleDist = qwtCeil( sd->extent( font() ) );
258 scaleDist++; // margin
259
260 rect.adjust( scaleDist, scaleDist, -scaleDist, -scaleDist );
261 }
262
263 return rect;
264}
265
279{
280 if ( mode != m_data->mode )
281 {
283
284 m_data->mode = mode;
285 sliderChange();
286 }
287}
288
294{
295 return m_data->mode;
296}
297
302{
303 m_data->pixmapCache = QPixmap();
304}
305
310void QwtDial::paintEvent( QPaintEvent* event )
311{
312 QPainter painter( this );
313 painter.setClipRegion( event->region() );
314
315 QStyleOption opt;
316 opt.initFrom(this);
317 style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
318
319 if ( m_data->mode == QwtDial::RotateScale )
320 {
321 painter.save();
322 painter.setRenderHint( QPainter::Antialiasing, true );
323
324 drawContents( &painter );
325
326 painter.restore();
327 }
328
329 const QRect r = contentsRect();
330 if ( r.size() != m_data->pixmapCache.size() )
331 {
332 m_data->pixmapCache = QwtPainter::backingStore( this, r.size() );
333 m_data->pixmapCache.fill( Qt::transparent );
334
335 QPainter p( &m_data->pixmapCache );
336 p.setRenderHint( QPainter::Antialiasing, true );
337 p.translate( -r.topLeft() );
338
339 if ( m_data->mode != QwtDial::RotateScale )
340 drawContents( &p );
341
342 if ( lineWidth() > 0 )
343 drawFrame( &p );
344
345 if ( m_data->mode != QwtDial::RotateNeedle )
346 drawNeedle( &p );
347 }
348
349 painter.drawPixmap( r.topLeft(), m_data->pixmapCache );
350
351 if ( m_data->mode == QwtDial::RotateNeedle )
352 drawNeedle( &painter );
353
354 if ( hasFocus() )
355 drawFocusIndicator( &painter );
356}
357
362void QwtDial::drawFocusIndicator( QPainter* painter ) const
363{
364 QwtPainter::drawFocusRect( painter, this, boundingRect() );
365}
366
373void QwtDial::drawFrame( QPainter* painter )
374{
376 palette(), lineWidth(), m_data->frameShadow );
377}
378
391void QwtDial::drawContents( QPainter* painter ) const
392{
393 if ( testAttribute( Qt::WA_NoSystemBackground ) ||
394 palette().brush( QPalette::Base ) !=
395 palette().brush( QPalette::Window ) )
396 {
397 const QRectF br = boundingRect();
398
399 painter->save();
400 painter->setPen( Qt::NoPen );
401 painter->setBrush( palette().brush( QPalette::Base ) );
402 painter->drawEllipse( br );
403 painter->restore();
404 }
405
406 const QRectF insideScaleRect = scaleInnerRect();
407 if ( palette().brush( QPalette::WindowText ) !=
408 palette().brush( QPalette::Base ) )
409 {
410 painter->save();
411 painter->setPen( Qt::NoPen );
412 painter->setBrush( palette().brush( QPalette::WindowText ) );
413 painter->drawEllipse( insideScaleRect );
414 painter->restore();
415 }
416
417 const QPointF center = insideScaleRect.center();
418 const double radius = 0.5 * insideScaleRect.width();
419
420 painter->save();
421 drawScale( painter, center, radius );
422 painter->restore();
423
424 painter->save();
425 drawScaleContents( painter, center, radius );
426 painter->restore();
427}
428
438void QwtDial::drawNeedle( QPainter* painter, const QPointF& center,
439 double radius, double direction, QPalette::ColorGroup colorGroup ) const
440{
441 if ( m_data->needle )
442 {
443 direction = 360.0 - direction; // counter clockwise
444 m_data->needle->draw( painter, center, radius, direction, colorGroup );
445 }
446}
447
448void QwtDial::drawNeedle( QPainter* painter ) const
449{
450 if ( !isValid() )
451 return;
452
453 QPalette::ColorGroup colorGroup;
454 if ( isEnabled() )
455 colorGroup = hasFocus() ? QPalette::Active : QPalette::Inactive;
456 else
457 colorGroup = QPalette::Disabled;
458
459 const QRectF sr = scaleInnerRect();
460
461 painter->save();
462 painter->setRenderHint( QPainter::Antialiasing, true );
463 drawNeedle( painter, sr.center(), 0.5 * sr.width(),
464 scaleMap().transform( value() ) + 270.0, colorGroup );
465 painter->restore();
466}
467
475void QwtDial::drawScale( QPainter* painter,
476 const QPointF& center, double radius ) const
477{
478 QwtRoundScaleDraw* sd = const_cast< QwtRoundScaleDraw* >( scaleDraw() );
479 if ( sd == NULL )
480 return;
481
482 sd->setRadius( radius );
483 sd->moveCenter( center );
484
485 QPalette pal = palette();
486
487 const QColor textColor = pal.color( QPalette::Text );
488 pal.setColor( QPalette::WindowText, textColor ); // ticks, backbone
489
490 painter->setFont( font() );
491 painter->setPen( QPen( textColor, sd->penWidthF() ) );
492
493 painter->setBrush( Qt::red );
494 sd->draw( painter, pal );
495}
496
506void QwtDial::drawScaleContents( QPainter* painter,
507 const QPointF& center, double radius ) const
508{
509 Q_UNUSED(painter);
510 Q_UNUSED(center);
511 Q_UNUSED(radius);
512}
513
523{
524 if ( needle != m_data->needle )
525 {
526 if ( m_data->needle )
527 delete m_data->needle;
528
529 m_data->needle = needle;
530 update();
531 }
532}
533
539{
540 return m_data->needle;
541}
542
548{
549 return m_data->needle;
550}
551
554{
555 return static_cast< QwtRoundScaleDraw* >( abstractScaleDraw() );
556}
557
560{
561 return static_cast< const QwtRoundScaleDraw* >( abstractScaleDraw() );
562}
563
579
588void QwtDial::setScaleArc( double minArc, double maxArc )
589{
590 if ( minArc != 360.0 && minArc != -360.0 )
591 minArc = std::fmod( minArc, 360.0 );
592 if ( maxArc != 360.0 && maxArc != -360.0 )
593 maxArc = std::fmod( maxArc, 360.0 );
594
595 double minScaleArc = qwtMinF( minArc, maxArc );
596 double maxScaleArc = qwtMaxF( minArc, maxArc );
597
598 if ( maxScaleArc - minScaleArc > 360.0 )
599 maxScaleArc = minScaleArc + 360.0;
600
601 if ( ( minScaleArc != m_data->minScaleArc ) ||
602 ( maxScaleArc != m_data->maxScaleArc ) )
603 {
604 m_data->minScaleArc = minScaleArc;
605 m_data->maxScaleArc = maxScaleArc;
606
608 sliderChange();
609 }
610}
611
618void QwtDial::setMinScaleArc( double min )
619{
620 setScaleArc( min, m_data->maxScaleArc );
621}
622
628{
629 return m_data->minScaleArc;
630}
631
638void QwtDial::setMaxScaleArc( double max )
639{
640 setScaleArc( m_data->minScaleArc, max );
641}
642
648{
649 return m_data->maxScaleArc;
650}
651
660void QwtDial::setOrigin( double origin )
661{
663
664 m_data->origin = origin;
665 sliderChange();
666}
667
674double QwtDial::origin() const
675{
676 return m_data->origin;
677}
678
683QSize QwtDial::sizeHint() const
684{
685 int sh = 0;
686 if ( scaleDraw() )
687 sh = qwtCeil( scaleDraw()->extent( font() ) );
688
689 const int d = 6 * sh + 2 * lineWidth();
690
691 QSize hint( d, d );
692 if ( !isReadOnly() )
693 hint = qwtExpandedToGlobalStrut( hint );
694
695 return hint;
696}
697
703{
704 int sh = 0;
705 if ( scaleDraw() )
706 sh = qwtCeil( scaleDraw()->extent( font() ) );
707
708 const int d = 3 * sh + 2 * lineWidth();
709
710 return QSize( d, d );
711}
712
721bool QwtDial::isScrollPosition( const QPoint& pos ) const
722{
723 const QRegion region( innerRect(), QRegion::Ellipse );
724 if ( region.contains( pos ) && ( pos != innerRect().center() ) )
725 {
726 double angle = QLineF( rect().center(), pos ).angle();
727 if ( m_data->mode == QwtDial::RotateScale )
728 angle = 360.0 - angle;
729
730 double valueAngle =
731 qwtNormalizeDegrees( 90.0 - scaleMap().transform( value() ) );
732
733 m_data->mouseOffset = qwtNormalizeDegrees( angle - valueAngle );
734 m_data->arcOffset = scaleMap().p1();
735
736 return true;
737 }
738
739 return false;
740}
741
751double QwtDial::scrolledTo( const QPoint& pos ) const
752{
753 double angle = QLineF( rect().center(), pos ).angle();
754 if ( m_data->mode == QwtDial::RotateScale )
755 {
756 angle += scaleMap().p1() - m_data->arcOffset;
757 angle = 360.0 - angle;
758 }
759
760 angle = qwtNormalizeDegrees( angle - m_data->mouseOffset );
761 angle = qwtNormalizeDegrees( 90.0 - angle );
762
763 if ( scaleMap().pDist() >= 360.0 )
764 {
765 if ( angle < scaleMap().p1() )
766 angle += 360.0;
767
768 if ( !wrapping() )
769 {
770 double boundedAngle = angle;
771
772 const double arc = angle - scaleMap().transform( value() );
773 if ( qAbs( arc ) > 180.0 )
774 {
775 boundedAngle = ( arc > 0 )
776 ? scaleMap().p1() : scaleMap().p2();
777 }
778
779 m_data->mouseOffset += ( boundedAngle - angle );
780
781 angle = boundedAngle;
782 }
783 }
784 else
785 {
786 const double boundedAngle =
787 qwtBoundedAngle( scaleMap().p1(), angle, scaleMap().p2() );
788
789 if ( !wrapping() )
790 m_data->mouseOffset += ( boundedAngle - angle );
791
792 angle = boundedAngle;
793 }
794
795 return scaleMap().invTransform( angle );
796}
797
804void QwtDial::changeEvent( QEvent* event )
805{
806 switch( event->type() )
807 {
808 case QEvent::EnabledChange:
809 case QEvent::FontChange:
810 case QEvent::StyleChange:
811 case QEvent::PaletteChange:
812 case QEvent::LanguageChange:
813 case QEvent::LocaleChange:
814 {
816 break;
817 }
818 default:
819 break;
820 }
821
823}
824
829void QwtDial::wheelEvent( QWheelEvent* event )
830{
831#if QT_VERSION < 0x050e00
832 const QPoint wheelPos = event->pos();
833#else
834 const QPoint wheelPos = event->position().toPoint();
835#endif
836
837 const QRegion region( innerRect(), QRegion::Ellipse );
838 if ( region.contains( wheelPos ) )
840}
841
842void QwtDial::setAngleRange( double angle, double span )
843{
844 if ( QwtRoundScaleDraw* sd = scaleDraw() )
845 {
846 angle = qwtNormalizeDegrees( angle - 270.0 );
847 sd->setAngleRange( angle, angle + span );
848 }
849}
850
860
862{
863 setAngleRange( m_data->origin + m_data->minScaleArc,
864 m_data->maxScaleArc - m_data->minScaleArc );
865
866 if ( mode() == RotateScale )
867 {
868 const double arc = scaleMap().transform( value() ) - scaleMap().p1();
869 setAngleRange( m_data->origin - arc,
870 m_data->maxScaleArc - m_data->minScaleArc );
871 }
872
874}
875
876#include "moc_qwt_dial.cpp"
A abstract base class for drawing scales.
virtual double extent(const QFont &font) const =0
virtual void draw(QPainter *, const QPalette &) const
Draw the scale.
const QwtScaleMap & scaleMap() const
void setScaleMaxMajor(int ticks)
Set the maximum number of major tick intervals.
const QwtAbstractScaleDraw * abstractScaleDraw() const
void setScaleMaxMinor(int ticks)
Set the maximum number of minor tick intervals.
int transform(double) const
void setAbstractScaleDraw(QwtAbstractScaleDraw *)
Set a scale draw.
virtual void changeEvent(QEvent *) override
An abstract base class for slider widgets with a scale.
virtual void scaleChange() override
virtual void sliderChange()
Calling update()
void setValue(double value)
virtual void wheelEvent(QWheelEvent *) override
double value() const
Returns the current value.
void setMinScaleArc(double)
Definition qwt_dial.cpp:618
virtual void drawFrame(QPainter *)
Definition qwt_dial.cpp:373
double minScaleArc() const
Definition qwt_dial.cpp:627
virtual ~QwtDial()
Destructor.
Definition qwt_dial.cpp:159
double maxScaleArc() const
Definition qwt_dial.cpp:647
void setFrameShadow(Shadow)
Definition qwt_dial.cpp:170
virtual void wheelEvent(QWheelEvent *) override
Definition qwt_dial.cpp:829
virtual QSize sizeHint() const override
Definition qwt_dial.cpp:683
void setScaleDraw(QwtRoundScaleDraw *)
Definition qwt_dial.cpp:574
virtual QRect scaleInnerRect() const
Definition qwt_dial.cpp:250
virtual void setOrigin(double)
Change the origin.
Definition qwt_dial.cpp:660
virtual void changeEvent(QEvent *) override
Definition qwt_dial.cpp:804
virtual void scaleChange() override
Definition qwt_dial.cpp:855
double origin() const
Definition qwt_dial.cpp:674
QRect boundingRect() const
Definition qwt_dial.cpp:234
virtual void drawScale(QPainter *, const QPointF &center, double radius) const
Definition qwt_dial.cpp:475
const QwtDialNeedle * needle() const
Definition qwt_dial.cpp:538
void setMode(Mode)
Change the mode of the dial.
Definition qwt_dial.cpp:278
Mode
Mode controlling whether the needle or the scale is rotating.
Definition qwt_dial.h:87
@ RotateScale
The needle is fixed, the scales are rotating.
Definition qwt_dial.h:92
@ RotateNeedle
The needle is rotating.
Definition qwt_dial.h:89
Shadow
Frame shadow.
Definition qwt_dial.h:74
@ Sunken
QFrame::Sunken.
Definition qwt_dial.h:82
void setLineWidth(int)
Definition qwt_dial.cpp:197
virtual bool isScrollPosition(const QPoint &) const override
Determine what to do when the user presses a mouse button.
Definition qwt_dial.cpp:721
Mode mode() const
Definition qwt_dial.cpp:293
virtual double scrolledTo(const QPoint &) const override
Determine the value for a new position of the slider handle.
Definition qwt_dial.cpp:751
void invalidateCache()
Definition qwt_dial.cpp:301
int lineWidth() const
Definition qwt_dial.cpp:215
QwtDial(QWidget *parent=NULL)
Constructor.
Definition qwt_dial.cpp:124
virtual void drawFocusIndicator(QPainter *) const
Definition qwt_dial.cpp:362
virtual void sliderChange() override
Calling update()
Definition qwt_dial.cpp:861
virtual QSize minimumSizeHint() const override
Definition qwt_dial.cpp:702
Shadow frameShadow() const
Definition qwt_dial.cpp:186
virtual void paintEvent(QPaintEvent *) override
Definition qwt_dial.cpp:310
void setNeedle(QwtDialNeedle *)
Definition qwt_dial.cpp:522
virtual void drawNeedle(QPainter *, const QPointF &, double radius, double direction, QPalette::ColorGroup) const
Definition qwt_dial.cpp:438
void setScaleArc(double minArc, double maxArc)
Definition qwt_dial.cpp:588
QwtRoundScaleDraw * scaleDraw()
Definition qwt_dial.cpp:553
virtual void drawScaleContents(QPainter *painter, const QPointF &center, double radius) const
Definition qwt_dial.cpp:506
QRect innerRect() const
Definition qwt_dial.cpp:224
virtual void drawContents(QPainter *) const
Draw the contents inside the frame.
Definition qwt_dial.cpp:391
void setMaxScaleArc(double)
Definition qwt_dial.cpp:638
Base class for needles that can be used in a QwtDial.
virtual void draw(QPainter *, const QPointF &center, double length, double direction, QPalette::ColorGroup=QPalette::Active) const
static void drawRoundFrame(QPainter *, const QRectF &, const QPalette &, int lineWidth, int frameStyle)
static void drawFocusRect(QPainter *, const QWidget *)
Draw a focus rectangle on a widget using its style.
static QPixmap backingStore(QWidget *, const QSize &)
A class for drawing round scales.
void setRadius(double radius)
void moveCenter(double x, double y)
Move the center of the scale draw, leaving the radius unchanged.
double p1() const
double transform(double s) const
double invTransform(double p) const
double p2() const