qwt_knob.cpp
Go to the documentation of this file.
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_knob.h"
11 #include "qwt_round_scale_draw.h"
12 #include "qwt_painter.h"
13 #include "qwt_scale_map.h"
14 #include "qwt_math.h"
15 #include "qwt.h"
16 
17 #include <qpainter.h>
18 #include <qpalette.h>
19 #include <qstyle.h>
20 #include <qstyleoption.h>
21 #include <qevent.h>
22 #include <qmargins.h>
23 #include <qmath.h>
24 
25 static QSize qwtKnobSizeHint( const QwtKnob *knob, int min )
26 {
27  int knobWidth = knob->knobWidth();
28  if ( knobWidth <= 0 )
29  knobWidth = qMax( 3 * knob->markerSize(), min );
30 
31  // Add the scale radial thickness to the knobWidth
32  const int extent = qwtCeil( knob->scaleDraw()->extent( knob->font() ) );
33  const int d = 2 * ( extent + 4 ) + knobWidth;
34 
35  const QMargins m = knob->contentsMargins();
36  return QSize( d + m.left() + m.right(), d + m.top() + m.bottom() );
37 }
38 
39 static inline double qwtToScaleAngle( double angle )
40 {
41  // the map is counter clockwise with the origin
42  // at 90° using angles from -180° -> 180°
43 
44  double a = 90.0 - angle;
45  if ( a <= -180.0 )
46  a += 360.0;
47  else if ( a >= 180.0 )
48  a -= 360.0;
49 
50  return a;
51 }
52 
53 static double qwtToDegrees( double value )
54 {
55  return qwtNormalizeDegrees( 90.0 - value );
56 }
57 
59 {
60 public:
64  borderWidth( 2 ),
65  borderDist( 4 ),
66  scaleDist( 4 ),
67  maxScaleTicks( 11 ),
68  knobWidth( 0 ),
69  alignment( Qt::AlignCenter ),
70  markerSize( 8 ),
71  totalAngle( 270.0 ),
72  mouseOffset( 0.0 )
73  {
74  }
75 
78 
81  int scaleDist;
83  int knobWidth;
84  Qt::Alignment alignment;
86 
87  double totalAngle;
88 
89  double mouseOffset;
90 };
91 
103 QwtKnob::QwtKnob( QWidget* parent ):
104  QwtAbstractSlider( parent )
105 {
106  d_data = new PrivateData;
107 
109 
110  setTotalAngle( 270.0 );
111 
112  setScale( 0.0, 10.0 );
113  setValue( 0.0 );
114 
115  setSizePolicy( QSizePolicy::MinimumExpanding,
116  QSizePolicy::MinimumExpanding );
117 }
118 
121 {
122  delete d_data;
123 }
124 
132 {
133  if ( d_data->knobStyle != knobStyle )
134  {
136  update();
137  }
138 }
139 
145 {
146  return d_data->knobStyle;
147 }
148 
156 {
157  if ( d_data->markerStyle != markerStyle )
158  {
160  update();
161  }
162 }
163 
169 {
170  return d_data->markerStyle;
171 }
172 
185 void QwtKnob::setTotalAngle ( double angle )
186 {
187  angle = qBound( 10.0, angle, 360.0 );
188 
189  if ( angle != d_data->totalAngle )
190  {
191  d_data->totalAngle = angle;
192 
194  0.5 * d_data->totalAngle );
195 
196  updateGeometry();
197  update();
198  }
199 }
200 
205 double QwtKnob::totalAngle() const
206 {
207  return d_data->totalAngle;
208 }
209 
220 {
221  numTurns = qMax( numTurns, 1 );
222 
223  if ( numTurns == 1 && d_data->totalAngle <= 360.0 )
224  return;
225 
226  const double angle = numTurns * 360.0;
227  if ( angle != d_data->totalAngle )
228  {
229  d_data->totalAngle = angle;
230 
232  0.5 * d_data->totalAngle );
233 
234  updateGeometry();
235  update();
236  }
237 }
238 
245 int QwtKnob::numTurns() const
246 {
247  return qwtCeil( d_data->totalAngle / 360.0 );
248 }
249 
260 {
261  setAbstractScaleDraw( scaleDraw );
263 
264  updateGeometry();
265  update();
266 }
267 
273 {
274  return static_cast<const QwtRoundScaleDraw *>( abstractScaleDraw() );
275 }
276 
282 {
283  return static_cast<QwtRoundScaleDraw *>( abstractScaleDraw() );
284 }
285 
292 QRect QwtKnob::knobRect() const
293 {
294  const QRect cr = contentsRect();
295 
296  const int extent = qwtCeil( scaleDraw()->extent( font() ) );
297  const int d = extent + d_data->scaleDist;
298 
299  int w = d_data->knobWidth;
300  if ( w <= 0 )
301  {
302  const int dim = qMin( cr.width(), cr.height() );
303 
304  w = dim - 2 * ( d );
305  w = qMax( 0, w );
306  }
307 
308  QRect r( 0, 0, w, w );
309 
310  if ( d_data->alignment & Qt::AlignLeft )
311  {
312  r.moveLeft( cr.left() + d );
313  }
314  else if ( d_data->alignment & Qt::AlignRight )
315  {
316  r.moveRight( cr.right() - d );
317  }
318  else
319  {
320  r.moveCenter( QPoint( cr.center().x(), r.center().y() ) );
321  }
322 
323  if ( d_data->alignment & Qt::AlignTop )
324  {
325  r.moveTop( cr.top() + d );
326  }
327  else if ( d_data->alignment & Qt::AlignBottom )
328  {
329  r.moveBottom( cr.bottom() - d );
330  }
331  else
332  {
333  r.moveCenter( QPoint( r.center().x(), cr.center().y() ) );
334  }
335 
336  return r;
337 }
338 
347 bool QwtKnob::isScrollPosition( const QPoint &pos ) const
348 {
349  const QRect kr = knobRect();
350 
351  const QRegion region( kr, QRegion::Ellipse );
352  if ( region.contains( pos ) && ( pos != kr.center() ) )
353  {
354  const double angle = QLineF( kr.center(), pos ).angle();
355  const double valueAngle = qwtToDegrees( scaleMap().transform( value() ) );
356 
357  d_data->mouseOffset = qwtNormalizeDegrees( angle - valueAngle );
358 
359  return true;
360  }
361 
362  return false;
363 }
364 
373 double QwtKnob::scrolledTo( const QPoint &pos ) const
374 {
375  double angle = QLineF( rect().center(), pos ).angle();
376  angle = qwtNormalizeDegrees( angle - d_data->mouseOffset );
377 
378  if ( scaleMap().pDist() > 360.0 )
379  {
380  angle = qwtToDegrees( angle );
381 
382  const double v = scaleMap().transform( value() );
383 
384  int numTurns = qwtFloor( ( v - scaleMap().p1() ) / 360.0 );
385 
386  double valueAngle = qwtNormalizeDegrees( v );
387  if ( qAbs( valueAngle - angle ) > 180.0 )
388  {
389  numTurns += ( angle > valueAngle ) ? -1 : 1;
390  }
391 
392  angle += scaleMap().p1() + numTurns * 360.0;
393 
394  if ( !wrapping() )
395  {
396  const double boundedAngle =
397  qBound( scaleMap().p1(), angle, scaleMap().p2() );
398 
399  d_data->mouseOffset += ( boundedAngle - angle );
400  angle = boundedAngle;
401  }
402  }
403  else
404  {
405  angle = qwtToScaleAngle( angle );
406 
407  double boundedAngle = qBound( scaleMap().p1(), angle, scaleMap().p2() );
408 
409  if ( !wrapping() )
410  {
411  const double currentAngle = scaleMap().transform( value() );
412 
413  if ( ( currentAngle > 90.0 ) && ( boundedAngle < -90.0 ) )
414  boundedAngle = scaleMap().p2();
415  else if ( ( currentAngle < -90.0 ) && ( boundedAngle > 90.0 ) )
416  boundedAngle = scaleMap().p1();
417 
418  d_data->mouseOffset += ( boundedAngle - angle );
419  }
420 
421  angle = boundedAngle;
422  }
423 
424  return scaleMap().invTransform( angle );
425 }
426 
431 void QwtKnob::changeEvent( QEvent *event )
432 {
433  switch( event->type() )
434  {
435  case QEvent::StyleChange:
436  case QEvent::FontChange:
437  {
438  updateGeometry();
439  update();
440  break;
441  }
442  default:
443  break;
444  }
445 }
446 
451 void QwtKnob::paintEvent( QPaintEvent *event )
452 {
453  const QRectF knobRect = this->knobRect();
454 
455  QPainter painter( this );
456  painter.setClipRegion( event->region() );
457 
458  QStyleOption opt;
459  opt.initFrom(this);
460  style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
461 
462  painter.setRenderHint( QPainter::Antialiasing, true );
463 
464  if ( !knobRect.contains( event->region().boundingRect() ) )
465  {
466  scaleDraw()->setRadius( 0.5 * knobRect.width() + d_data->scaleDist );
467  scaleDraw()->moveCenter( knobRect.center() );
468 
469  scaleDraw()->draw( &painter, palette() );
470  }
471 
472  drawKnob( &painter, knobRect );
473 
474  drawMarker( &painter, knobRect,
476 
477  painter.setRenderHint( QPainter::Antialiasing, false );
478 
479  if ( hasFocus() )
480  drawFocusIndicator( &painter );
481 }
482 
489 void QwtKnob::drawKnob( QPainter *painter, const QRectF &knobRect ) const
490 {
491  double dim = qMin( knobRect.width(), knobRect.height() );
492  dim -= d_data->borderWidth * 0.5;
493 
494  QRectF aRect( 0, 0, dim, dim );
495  aRect.moveCenter( knobRect.center() );
496 
497  QPen pen( Qt::NoPen );
498  if ( d_data->borderWidth > 0 )
499  {
500  QColor c1 = palette().color( QPalette::Light );
501  QColor c2 = palette().color( QPalette::Dark );
502 
503  QLinearGradient gradient( aRect.topLeft(), aRect.bottomRight() );
504  gradient.setColorAt( 0.0, c1 );
505  gradient.setColorAt( 0.3, c1 );
506  gradient.setColorAt( 0.7, c2 );
507  gradient.setColorAt( 1.0, c2 );
508 
509  pen = QPen( gradient, d_data->borderWidth );
510  }
511 
512  QBrush brush;
513  switch( d_data->knobStyle )
514  {
515  case QwtKnob::Raised:
516  {
517  double off = 0.3 * knobRect.width();
518  QRadialGradient gradient( knobRect.center(),
519  knobRect.width(), knobRect.topLeft() + QPointF( off, off ) );
520 
521  gradient.setColorAt( 0.0, palette().color( QPalette::Midlight ) );
522  gradient.setColorAt( 1.0, palette().color( QPalette::Button ) );
523 
524  brush = QBrush( gradient );
525 
526  break;
527  }
528  case QwtKnob::Styled:
529  {
530  QRadialGradient gradient(knobRect.center().x() - knobRect.width() / 3,
531  knobRect.center().y() - knobRect.height() / 2,
532  knobRect.width() * 1.3,
533  knobRect.center().x(),
534  knobRect.center().y() - knobRect.height() / 2);
535 
536  const QColor c = palette().color( QPalette::Button );
537  gradient.setColorAt(0, c.lighter(110));
538  gradient.setColorAt( 0.5, c);
539  gradient.setColorAt( 0.501, c.darker(102));
540  gradient.setColorAt(1, c.darker(115));
541 
542  brush = QBrush( gradient );
543 
544  break;
545  }
546  case QwtKnob::Sunken:
547  {
548  QLinearGradient gradient(
549  knobRect.topLeft(), knobRect.bottomRight() );
550  gradient.setColorAt( 0.0, palette().color( QPalette::Mid ) );
551  gradient.setColorAt( 0.5, palette().color( QPalette::Button ) );
552  gradient.setColorAt( 1.0, palette().color( QPalette::Midlight ) );
553  brush = QBrush( gradient );
554 
555  break;
556  }
557  case QwtKnob::Flat:
558  default:
559  brush = palette().brush( QPalette::Button );
560  }
561 
562  painter->setPen( pen );
563  painter->setBrush( brush );
564  painter->drawEllipse( aRect );
565 }
566 
567 
576 void QwtKnob::drawMarker( QPainter *painter,
577  const QRectF &rect, double angle ) const
578 {
579  if ( d_data->markerStyle == NoMarker || !isValid() )
580  return;
581 
582  const double radians = qwtRadians( angle );
583  const double sinA = -qFastSin( radians );
584  const double cosA = qFastCos( radians );
585 
586  const double xm = rect.center().x();
587  const double ym = rect.center().y();
588  const double margin = 4.0;
589 
590  double radius = 0.5 * ( rect.width() - d_data->borderWidth ) - margin;
591  if ( radius < 1.0 )
592  radius = 1.0;
593 
594  double markerSize = d_data->markerSize;
595  if ( markerSize <= 0 )
596  markerSize = qRound( 0.4 * radius );
597 
598  switch ( d_data->markerStyle )
599  {
600  case Notch:
601  case Nub:
602  {
603  const double dotWidth = qwtMinF( markerSize, radius );
604 
605  const double dotCenterDist = radius - 0.5 * dotWidth;
606  if ( dotCenterDist > 0.0 )
607  {
608  const QPointF center( xm - sinA * dotCenterDist,
609  ym - cosA * dotCenterDist );
610 
611  QRectF ellipse( 0.0, 0.0, dotWidth, dotWidth );
612  ellipse.moveCenter( center );
613 
614  QColor c1 = palette().color( QPalette::Light );
615  QColor c2 = palette().color( QPalette::Mid );
616 
617  if ( d_data->markerStyle == Notch )
618  qSwap( c1, c2 );
619 
620  QLinearGradient gradient(
621  ellipse.topLeft(), ellipse.bottomRight() );
622  gradient.setColorAt( 0.0, c1 );
623  gradient.setColorAt( 1.0, c2 );
624 
625  painter->setPen( Qt::NoPen );
626  painter->setBrush( gradient );
627 
628  painter->drawEllipse( ellipse );
629  }
630  break;
631  }
632  case Dot:
633  {
634  const double dotWidth = qwtMinF( markerSize, radius);
635 
636  const double dotCenterDist = radius - 0.5 * dotWidth;
637  if ( dotCenterDist > 0.0 )
638  {
639  const QPointF center( xm - sinA * dotCenterDist,
640  ym - cosA * dotCenterDist );
641 
642  QRectF ellipse( 0.0, 0.0, dotWidth, dotWidth );
643  ellipse.moveCenter( center );
644 
645  painter->setPen( Qt::NoPen );
646  painter->setBrush( palette().color( QPalette::ButtonText ) );
647  painter->drawEllipse( ellipse );
648  }
649 
650  break;
651  }
652  case Tick:
653  {
654  const double rb = qwtMaxF( radius - markerSize, 1.0 );
655  const double re = radius;
656 
657  const QLineF line( xm - sinA * rb, ym - cosA * rb,
658  xm - sinA * re, ym - cosA * re );
659 
660  QPen pen( palette().color( QPalette::ButtonText ), 0 );
661  pen.setCapStyle( Qt::FlatCap );
662  painter->setPen( pen );
663  painter->drawLine ( line );
664 
665  break;
666  }
667  case Triangle:
668  {
669  const double rb = qwtMaxF( radius - markerSize, 1.0 );
670  const double re = radius;
671 
672  painter->translate( rect.center() );
673  painter->rotate( angle - 90.0 );
674 
675  QPolygonF polygon;
676  polygon += QPointF( re, 0.0 );
677  polygon += QPointF( rb, 0.5 * ( re - rb ) );
678  polygon += QPointF( rb, -0.5 * ( re - rb ) );
679 
680  painter->setPen( Qt::NoPen );
681  painter->setBrush( palette().color( QPalette::ButtonText ) );
682  painter->drawPolygon( polygon );
683 
684  painter->resetTransform();
685 
686  break;
687  }
688  default:
689  break;
690  }
691 }
692 
697 void QwtKnob::drawFocusIndicator( QPainter *painter ) const
698 {
699  const QRect cr = contentsRect();
700 
701  int w = d_data->knobWidth;
702  if ( w <= 0 )
703  {
704  w = qMin( cr.width(), cr.height() );
705  }
706  else
707  {
708  const int extent = qCeil( scaleDraw()->extent( font() ) );
709  w += 2 * ( extent + d_data->scaleDist );
710  }
711 
712  QRect focusRect( 0, 0, w, w );
713  focusRect.moveCenter( cr.center() );
714 
715  QwtPainter::drawFocusRect( painter, this, focusRect );
716 }
717 
730 void QwtKnob::setAlignment( Qt::Alignment alignment )
731 {
732  if ( d_data->alignment != alignment )
733  {
735  update();
736  }
737 }
738 
743 Qt::Alignment QwtKnob::alignment() const
744 {
745  return d_data->alignment;
746 }
747 
759 void QwtKnob::setKnobWidth( int width )
760 {
761  width = qMax( width, 0 );
762 
763  if ( width != d_data->knobWidth )
764  {
765  QSizePolicy::Policy policy;
766  if ( width > 0 )
767  policy = QSizePolicy::Minimum;
768  else
769  policy = QSizePolicy::MinimumExpanding;
770 
771  setSizePolicy( policy, policy );
772 
773  d_data->knobWidth = width;
774 
775  updateGeometry();
776  update();
777  }
778 }
779 
781 int QwtKnob::knobWidth() const
782 {
783  return d_data->knobWidth;
784 }
785 
791 {
792  d_data->borderWidth = qMax( borderWidth, 0 );
793 
794  updateGeometry();
795  update();
796 }
797 
799 int QwtKnob::borderWidth() const
800 {
801  return d_data->borderWidth;
802 }
803 
812 void QwtKnob::setMarkerSize( int size )
813 {
814  if ( d_data->markerSize != size )
815  {
816  d_data->markerSize = size;
817  update();
818  }
819 }
820 
825 int QwtKnob::markerSize() const
826 {
827  return d_data->markerSize;
828 }
829 
833 QSize QwtKnob::sizeHint() const
834 {
835  const QSize hint = qwtKnobSizeHint( this, 50 );
836  return qwtExpandedToGlobalStrut( hint );
837 }
838 
844 {
845  return qwtKnobSizeHint( this, 20 );
846 }
847 
848 #if QWT_MOC_INCLUDE
849 #include "moc_qwt_knob.cpp"
850 #endif
void setKnobStyle(KnobStyle)
Set the knob type.
Definition: qwt_knob.cpp:131
int knobWidth() const
double p1() const
Definition: qwt_scale_map.h:99
void setScale(double lowerBound, double upperBound)
Specify a scale.
Paint a circle in QPalette::ButtonText color.
Definition: qwt_knob.h:107
enum MQTTPropertyCodes value
void setKnobWidth(int)
Change the knob&#39;s width.
Definition: qwt_knob.cpp:759
double p2() const
static void drawFocusRect(QPainter *, const QWidget *)
Draw a focus rectangle on a widget using its style.
Paint a triangle in QPalette::ButtonText color.
Definition: qwt_knob.h:104
QRect knobRect() const
Definition: qwt_knob.cpp:292
void setAbstractScaleDraw(QwtAbstractScaleDraw *)
Set a scale draw.
int numTurns() const
int transform(double) const
int markerSize
Definition: qwt_knob.h:54
QSize qwtExpandedToGlobalStrut(const QSize &size)
Definition: qwt.cpp:21
MQTTClient d
Definition: test10.c:1656
QWT_CONSTEXPR float qwtMaxF(float a, float b)
Definition: qwt_math.h:123
virtual bool isScrollPosition(const QPoint &) const QWT_OVERRIDE
Determine what to do when the user presses a mouse button.
Definition: qwt_knob.cpp:347
void setValue(double value)
virtual void drawKnob(QPainter *, const QRectF &) const
Draw the knob.
Definition: qwt_knob.cpp:489
The Knob Widget.
Definition: qwt_knob.h:42
static QSize qwtKnobSizeHint(const QwtKnob *knob, int min)
Definition: qwt_knob.cpp:25
void setScaleDraw(QwtRoundScaleDraw *)
Definition: qwt_knob.cpp:259
Qt::Alignment alignment() const
const QwtScaleMap & scaleMap() const
QwtKnob(QWidget *parent=NULL)
Constructor.
Definition: qwt_knob.cpp:103
static double qwtToDegrees(double value)
Definition: qwt_knob.cpp:53
bool wrapping() const
MarkerStyle
Marker type.
Definition: qwt_knob.h:95
void setAlignment(Qt::Alignment)
Set the alignment of the knob.
Definition: qwt_knob.cpp:730
Don&#39;t paint any marker.
Definition: qwt_knob.h:98
QWT_CONSTEXPR float qwtMinF(float a, float b)
Definition: qwt_math.h:99
int qwtFloor(qreal value)
Definition: qwt_math.h:271
Qt::Alignment alignment
Definition: qwt_knob.cpp:84
virtual void drawFocusIndicator(QPainter *) const
Definition: qwt_knob.cpp:697
void moveCenter(double x, double y)
Move the center of the scale draw, leaving the radius unchanged.
PrivateData * d_data
Definition: qwt_knob.h:174
An abstract base class for slider widgets with a scale.
double value() const
const QwtRoundScaleDraw * scaleDraw() const
Definition: qwt_knob.cpp:272
int markerSize() const
virtual void drawMarker(QPainter *, const QRectF &, double angle) const
Draw the marker at the knob&#39;s front.
Definition: qwt_knob.cpp:576
#define min(A, B)
Definition: Log.c:64
double qwtRadians(double degrees)
Translate degrees into radians.
Definition: qwt_math.h:247
void setMarkerSize(int)
Set the size of the marker.
Definition: qwt_knob.cpp:812
KnobStyle
Style of the knob surface.
Definition: qwt_knob.h:66
KnobStyle knobStyle() const
Paint a single tick in QPalette::ButtonText color.
Definition: qwt_knob.h:101
double totalAngle() const
const QwtAbstractScaleDraw * abstractScaleDraw() const
virtual void changeEvent(QEvent *) QWT_OVERRIDE
Definition: qwt_knob.cpp:431
double invTransform(double p) const
virtual double extent(const QFont &) const QWT_OVERRIDE
QwtKnob::KnobStyle knobStyle
Definition: qwt_knob.cpp:76
void setAngleRange(double angle1, double angle2)
Adjust the baseline circle segment for round scales.
virtual QSize minimumSizeHint() const QWT_OVERRIDE
Definition: qwt_knob.cpp:843
virtual QSize sizeHint() const QWT_OVERRIDE
Definition: qwt_knob.cpp:833
A class for drawing round scales.
MQTTClient c
Definition: test10.c:1656
void setTotalAngle(double angle)
Set the total angle by which the knob can be turned.
Definition: qwt_knob.cpp:185
virtual void draw(QPainter *, const QPalette &) const
Draw the scale.
virtual ~QwtKnob()
Destructor.
Definition: qwt_knob.cpp:120
Build a gradient from QPalette::Midlight and QPalette::Button.
Definition: qwt_knob.h:72
static double qwtToScaleAngle(double angle)
Definition: qwt_knob.cpp:39
virtual double scrolledTo(const QPoint &) const QWT_OVERRIDE
Determine the value for a new position of the mouse.
Definition: qwt_knob.cpp:373
MarkerStyle markerStyle() const
void setBorderWidth(int)
Set the knob&#39;s border width.
Definition: qwt_knob.cpp:790
int knobWidth
Return the width of the knob.
Definition: qwt_knob.h:49
void setRadius(double radius)
double transform(double s) const
void setNumTurns(int)
Set the number of turns.
Definition: qwt_knob.cpp:219
double qwtNormalizeDegrees(double degrees)
Normalize an angle to be int the range [0.0, 360.0[.
Definition: qwt_math.cpp:35
int borderWidth() const
QwtKnob::MarkerStyle markerStyle
Definition: qwt_knob.cpp:77
Fill the knob with a brush from QPalette::Button.
Definition: qwt_knob.h:69
int qwtCeil(qreal value)
Definition: qwt_math.h:262
virtual void paintEvent(QPaintEvent *) QWT_OVERRIDE
Definition: qwt_knob.cpp:451
void setMarkerStyle(MarkerStyle)
Set the marker type of the knob.
Definition: qwt_knob.cpp:155


plotjuggler
Author(s): Davide Faconti
autogenerated on Sun Dec 6 2020 03:48:10