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_math.h"
13 #include "qwt_painter.h"
14 #include "qwt_scale_map.h"
15 #include <qpainter.h>
16 #include <qpalette.h>
17 #include <qstyle.h>
18 #include <qstyleoption.h>
19 #include <qevent.h>
20 #include <qmath.h>
21 #include <qapplication.h>
22 
23 #if QT_VERSION < 0x040601
24 #define qAtan2(y, x) ::atan2(y, x)
25 #define qFabs(x) ::fabs(x)
26 #define qFastCos(x) qCos(x)
27 #define qFastSin(x) qSin(x)
28 #endif
29 
30 static QSize qwtKnobSizeHint( const QwtKnob *knob, int min )
31 {
32  int knobWidth = knob->knobWidth();
33  if ( knobWidth <= 0 )
34  knobWidth = qMax( 3 * knob->markerSize(), min );
35 
36  // Add the scale radial thickness to the knobWidth
37  const int extent = qCeil( knob->scaleDraw()->extent( knob->font() ) );
38  const int d = 2 * ( extent + 4 ) + knobWidth;
39 
40  int left, right, top, bottom;
41  knob->getContentsMargins( &left, &top, &right, &bottom );
42 
43  return QSize( d + left + right, d + top + bottom );
44 }
45 
46 static inline double qwtToScaleAngle( double angle )
47 {
48  // the map is counter clockwise with the origin
49  // at 90° using angles from -180° -> 180°
50 
51  double a = 90.0 - angle;
52  if ( a <= -180.0 )
53  a += 360.0;
54  else if ( a >= 180.0 )
55  a -= 360.0;
56 
57  return a;
58 }
59 
60 static double qwtToDegrees( double value )
61 {
62  return qwtNormalizeDegrees( 90.0 - value );
63 }
64 
66 {
67 public:
71  borderWidth( 2 ),
72  borderDist( 4 ),
73  scaleDist( 4 ),
74  maxScaleTicks( 11 ),
75  knobWidth( 0 ),
76  alignment( Qt::AlignCenter ),
77  markerSize( 8 ),
78  totalAngle( 270.0 ),
79  mouseOffset( 0.0 )
80  {
81  }
82 
85 
88  int scaleDist;
90  int knobWidth;
91  Qt::Alignment alignment;
93 
94  double totalAngle;
95 
96  double mouseOffset;
97 };
98 
110 QwtKnob::QwtKnob( QWidget* parent ):
111  QwtAbstractSlider( parent )
112 {
113  d_data = new PrivateData;
114 
116 
117  setTotalAngle( 270.0 );
118 
119  setScale( 0.0, 10.0 );
120  setValue( 0.0 );
121 
122  setSizePolicy( QSizePolicy::MinimumExpanding,
123  QSizePolicy::MinimumExpanding );
124 }
125 
128 {
129  delete d_data;
130 }
131 
139 {
140  if ( d_data->knobStyle != knobStyle )
141  {
143  update();
144  }
145 }
146 
152 {
153  return d_data->knobStyle;
154 }
155 
163 {
164  if ( d_data->markerStyle != markerStyle )
165  {
167  update();
168  }
169 }
170 
176 {
177  return d_data->markerStyle;
178 }
179 
192 void QwtKnob::setTotalAngle ( double angle )
193 {
194  angle = qBound( 10.0, angle, 360.0 );
195 
196  if ( angle != d_data->totalAngle )
197  {
198  d_data->totalAngle = angle;
199 
201  0.5 * d_data->totalAngle );
202 
203  updateGeometry();
204  update();
205  }
206 }
207 
212 double QwtKnob::totalAngle() const
213 {
214  return d_data->totalAngle;
215 }
216 
227 {
228  numTurns = qMax( numTurns, 1 );
229 
230  if ( numTurns == 1 && d_data->totalAngle <= 360.0 )
231  return;
232 
233  const double angle = numTurns * 360.0;
234  if ( angle != d_data->totalAngle )
235  {
236  d_data->totalAngle = angle;
237 
239  0.5 * d_data->totalAngle );
240 
241  updateGeometry();
242  update();
243  }
244 }
245 
252 int QwtKnob::numTurns() const
253 {
254  return qCeil( d_data->totalAngle / 360.0 );
255 }
256 
267 {
268  setAbstractScaleDraw( scaleDraw );
270 
271  updateGeometry();
272  update();
273 }
274 
280 {
281  return static_cast<const QwtRoundScaleDraw *>( abstractScaleDraw() );
282 }
283 
289 {
290  return static_cast<QwtRoundScaleDraw *>( abstractScaleDraw() );
291 }
292 
299 QRect QwtKnob::knobRect() const
300 {
301  const QRect cr = contentsRect();
302 
303  const int extent = qCeil( scaleDraw()->extent( font() ) );
304  const int d = extent + d_data->scaleDist;
305 
306  int w = d_data->knobWidth;
307  if ( w <= 0 )
308  {
309  const int dim = qMin( cr.width(), cr.height() );
310 
311  w = dim - 2 * ( d );
312  w = qMax( 0, w );
313  }
314 
315  QRect r( 0, 0, w, w );
316 
317  if ( d_data->alignment & Qt::AlignLeft )
318  {
319  r.moveLeft( cr.left() + d );
320  }
321  else if ( d_data->alignment & Qt::AlignRight )
322  {
323  r.moveRight( cr.right() - d );
324  }
325  else
326  {
327  r.moveCenter( QPoint( cr.center().x(), r.center().y() ) );
328  }
329 
330  if ( d_data->alignment & Qt::AlignTop )
331  {
332  r.moveTop( cr.top() + d );
333  }
334  else if ( d_data->alignment & Qt::AlignBottom )
335  {
336  r.moveBottom( cr.bottom() - d );
337  }
338  else
339  {
340  r.moveCenter( QPoint( r.center().x(), cr.center().y() ) );
341  }
342 
343  return r;
344 }
345 
354 bool QwtKnob::isScrollPosition( const QPoint &pos ) const
355 {
356  const QRect kr = knobRect();
357 
358  const QRegion region( kr, QRegion::Ellipse );
359  if ( region.contains( pos ) && ( pos != kr.center() ) )
360  {
361  const double angle = QLineF( kr.center(), pos ).angle();
362  const double valueAngle = qwtToDegrees( scaleMap().transform( value() ) );
363 
364  d_data->mouseOffset = qwtNormalizeDegrees( angle - valueAngle );
365 
366  return true;
367  }
368 
369  return false;
370 }
371 
380 double QwtKnob::scrolledTo( const QPoint &pos ) const
381 {
382  double angle = QLineF( rect().center(), pos ).angle();
383  angle = qwtNormalizeDegrees( angle - d_data->mouseOffset );
384 
385  if ( scaleMap().pDist() > 360.0 )
386  {
387  angle = qwtToDegrees( angle );
388 
389  const double v = scaleMap().transform( value() );
390 
391  int numTurns = qFloor( ( v - scaleMap().p1() ) / 360.0 );
392 
393  double valueAngle = qwtNormalizeDegrees( v );
394  if ( qAbs( valueAngle - angle ) > 180.0 )
395  {
396  numTurns += ( angle > valueAngle ) ? -1 : 1;
397  }
398 
399  angle += scaleMap().p1() + numTurns * 360.0;
400 
401  if ( !wrapping() )
402  {
403  const double boundedAngle =
404  qBound( scaleMap().p1(), angle, scaleMap().p2() );
405 
406  d_data->mouseOffset += ( boundedAngle - angle );
407  angle = boundedAngle;
408  }
409  }
410  else
411  {
412  angle = qwtToScaleAngle( angle );
413 
414  double boundedAngle = qBound( scaleMap().p1(), angle, scaleMap().p2() );
415 
416  if ( !wrapping() )
417  {
418  const double currentAngle = scaleMap().transform( value() );
419 
420  if ( ( currentAngle > 90.0 ) && ( boundedAngle < -90.0 ) )
421  boundedAngle = scaleMap().p2();
422  else if ( ( currentAngle < -90.0 ) && ( boundedAngle > 90.0 ) )
423  boundedAngle = scaleMap().p1();
424 
425  d_data->mouseOffset += ( boundedAngle - angle );
426  }
427 
428  angle = boundedAngle;
429  }
430 
431  return scaleMap().invTransform( angle );
432 }
433 
438 void QwtKnob::changeEvent( QEvent *event )
439 {
440  switch( event->type() )
441  {
442  case QEvent::StyleChange:
443  case QEvent::FontChange:
444  {
445  updateGeometry();
446  update();
447  break;
448  }
449  default:
450  break;
451  }
452 }
453 
458 void QwtKnob::paintEvent( QPaintEvent *event )
459 {
460  const QRectF knobRect = this->knobRect();
461 
462  QPainter painter( this );
463  painter.setClipRegion( event->region() );
464 
465  QStyleOption opt;
466  opt.init(this);
467  style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
468 
469  painter.setRenderHint( QPainter::Antialiasing, true );
470 
471  if ( !knobRect.contains( event->region().boundingRect() ) )
472  {
473  scaleDraw()->setRadius( 0.5 * knobRect.width() + d_data->scaleDist );
474  scaleDraw()->moveCenter( knobRect.center() );
475 
476  scaleDraw()->draw( &painter, palette() );
477  }
478 
479  drawKnob( &painter, knobRect );
480 
481  drawMarker( &painter, knobRect,
483 
484  painter.setRenderHint( QPainter::Antialiasing, false );
485 
486  if ( hasFocus() )
487  drawFocusIndicator( &painter );
488 }
489 
496 void QwtKnob::drawKnob( QPainter *painter, const QRectF &knobRect ) const
497 {
498  double dim = qMin( knobRect.width(), knobRect.height() );
499  dim -= d_data->borderWidth * 0.5;
500 
501  QRectF aRect( 0, 0, dim, dim );
502  aRect.moveCenter( knobRect.center() );
503 
504  QPen pen( Qt::NoPen );
505  if ( d_data->borderWidth > 0 )
506  {
507  QColor c1 = palette().color( QPalette::Light );
508  QColor c2 = palette().color( QPalette::Dark );
509 
510  QLinearGradient gradient( aRect.topLeft(), aRect.bottomRight() );
511  gradient.setColorAt( 0.0, c1 );
512  gradient.setColorAt( 0.3, c1 );
513  gradient.setColorAt( 0.7, c2 );
514  gradient.setColorAt( 1.0, c2 );
515 
516  pen = QPen( gradient, d_data->borderWidth );
517  }
518 
519  QBrush brush;
520  switch( d_data->knobStyle )
521  {
522  case QwtKnob::Raised:
523  {
524  double off = 0.3 * knobRect.width();
525  QRadialGradient gradient( knobRect.center(),
526  knobRect.width(), knobRect.topLeft() + QPointF( off, off ) );
527 
528  gradient.setColorAt( 0.0, palette().color( QPalette::Midlight ) );
529  gradient.setColorAt( 1.0, palette().color( QPalette::Button ) );
530 
531  brush = QBrush( gradient );
532 
533  break;
534  }
535  case QwtKnob::Styled:
536  {
537  QRadialGradient gradient(knobRect.center().x() - knobRect.width() / 3,
538  knobRect.center().y() - knobRect.height() / 2,
539  knobRect.width() * 1.3,
540  knobRect.center().x(),
541  knobRect.center().y() - knobRect.height() / 2);
542 
543  const QColor c = palette().color( QPalette::Button );
544  gradient.setColorAt(0, c.lighter(110));
545  gradient.setColorAt(qreal(0.5), c);
546  gradient.setColorAt(qreal(0.501), c.darker(102));
547  gradient.setColorAt(1, c.darker(115));
548 
549  brush = QBrush( gradient );
550 
551  break;
552  }
553  case QwtKnob::Sunken:
554  {
555  QLinearGradient gradient(
556  knobRect.topLeft(), knobRect.bottomRight() );
557  gradient.setColorAt( 0.0, palette().color( QPalette::Mid ) );
558  gradient.setColorAt( 0.5, palette().color( QPalette::Button ) );
559  gradient.setColorAt( 1.0, palette().color( QPalette::Midlight ) );
560  brush = QBrush( gradient );
561 
562  break;
563  }
564  case QwtKnob::Flat:
565  default:
566  brush = palette().brush( QPalette::Button );
567  }
568 
569  painter->setPen( pen );
570  painter->setBrush( brush );
571  painter->drawEllipse( aRect );
572 }
573 
574 
583 void QwtKnob::drawMarker( QPainter *painter,
584  const QRectF &rect, double angle ) const
585 {
586  if ( d_data->markerStyle == NoMarker || !isValid() )
587  return;
588 
589  const double radians = qwtRadians( angle );
590  const double sinA = -qFastSin( radians );
591  const double cosA = qFastCos( radians );
592 
593  const double xm = rect.center().x();
594  const double ym = rect.center().y();
595  const double margin = 4.0;
596 
597  double radius = 0.5 * ( rect.width() - d_data->borderWidth ) - margin;
598  if ( radius < 1.0 )
599  radius = 1.0;
600 
602  if ( markerSize <= 0 )
603  markerSize = qRound( 0.4 * radius );
604 
605  switch ( d_data->markerStyle )
606  {
607  case Notch:
608  case Nub:
609  {
610  const double dotWidth =
611  qMin( double( markerSize ), radius);
612 
613  const double dotCenterDist = radius - 0.5 * dotWidth;
614  if ( dotCenterDist > 0.0 )
615  {
616  const QPointF center( xm - sinA * dotCenterDist,
617  ym - cosA * dotCenterDist );
618 
619  QRectF ellipse( 0.0, 0.0, dotWidth, dotWidth );
620  ellipse.moveCenter( center );
621 
622  QColor c1 = palette().color( QPalette::Light );
623  QColor c2 = palette().color( QPalette::Mid );
624 
625  if ( d_data->markerStyle == Notch )
626  qSwap( c1, c2 );
627 
628  QLinearGradient gradient(
629  ellipse.topLeft(), ellipse.bottomRight() );
630  gradient.setColorAt( 0.0, c1 );
631  gradient.setColorAt( 1.0, c2 );
632 
633  painter->setPen( Qt::NoPen );
634  painter->setBrush( gradient );
635 
636  painter->drawEllipse( ellipse );
637  }
638  break;
639  }
640  case Dot:
641  {
642  const double dotWidth =
643  qMin( double( markerSize ), radius);
644 
645  const double dotCenterDist = radius - 0.5 * dotWidth;
646  if ( dotCenterDist > 0.0 )
647  {
648  const QPointF center( xm - sinA * dotCenterDist,
649  ym - cosA * dotCenterDist );
650 
651  QRectF ellipse( 0.0, 0.0, dotWidth, dotWidth );
652  ellipse.moveCenter( center );
653 
654  painter->setPen( Qt::NoPen );
655  painter->setBrush( palette().color( QPalette::ButtonText ) );
656  painter->drawEllipse( ellipse );
657  }
658 
659  break;
660  }
661  case Tick:
662  {
663  const double rb = qMax( radius - markerSize, 1.0 );
664  const double re = radius;
665 
666  const QLineF line( xm - sinA * rb, ym - cosA * rb,
667  xm - sinA * re, ym - cosA * re );
668 
669  QPen pen( palette().color( QPalette::ButtonText ), 0 );
670  pen.setCapStyle( Qt::FlatCap );
671  painter->setPen( pen );
672  painter->drawLine ( line );
673 
674  break;
675  }
676  case Triangle:
677  {
678  const double rb = qMax( radius - markerSize, 1.0 );
679  const double re = radius;
680 
681  painter->translate( rect.center() );
682  painter->rotate( angle - 90.0 );
683 
684  QPolygonF polygon;
685  polygon += QPointF( re, 0.0 );
686  polygon += QPointF( rb, 0.5 * ( re - rb ) );
687  polygon += QPointF( rb, -0.5 * ( re - rb ) );
688 
689  painter->setPen( Qt::NoPen );
690  painter->setBrush( palette().color( QPalette::ButtonText ) );
691  painter->drawPolygon( polygon );
692 
693  painter->resetTransform();
694 
695  break;
696  }
697  default:
698  break;
699  }
700 }
701 
706 void QwtKnob::drawFocusIndicator( QPainter *painter ) const
707 {
708  const QRect cr = contentsRect();
709 
710  int w = d_data->knobWidth;
711  if ( w <= 0 )
712  {
713  w = qMin( cr.width(), cr.height() );
714  }
715  else
716  {
717  const int extent = qCeil( scaleDraw()->extent( font() ) );
718  w += 2 * ( extent + d_data->scaleDist );
719  }
720 
721  QRect focusRect( 0, 0, w, w );
722  focusRect.moveCenter( cr.center() );
723 
724  QwtPainter::drawFocusRect( painter, this, focusRect );
725 }
726 
739 void QwtKnob::setAlignment( Qt::Alignment alignment )
740 {
741  if ( d_data->alignment != alignment )
742  {
744  update();
745  }
746 }
747 
752 Qt::Alignment QwtKnob::alignment() const
753 {
754  return d_data->alignment;
755 }
756 
768 void QwtKnob::setKnobWidth( int width )
769 {
770  width = qMax( width, 0 );
771 
772  if ( width != d_data->knobWidth )
773  {
774  QSizePolicy::Policy policy;
775  if ( width > 0 )
776  policy = QSizePolicy::Minimum;
777  else
778  policy = QSizePolicy::MinimumExpanding;
779 
780  setSizePolicy( policy, policy );
781 
782  d_data->knobWidth = width;
783 
784  updateGeometry();
785  update();
786  }
787 }
788 
790 int QwtKnob::knobWidth() const
791 {
792  return d_data->knobWidth;
793 }
794 
800 {
801  d_data->borderWidth = qMax( borderWidth, 0 );
802 
803  updateGeometry();
804  update();
805 }
806 
808 int QwtKnob::borderWidth() const
809 {
810  return d_data->borderWidth;
811 }
812 
821 void QwtKnob::setMarkerSize( int size )
822 {
823  if ( d_data->markerSize != size )
824  {
825  d_data->markerSize = size;
826  update();
827  }
828 }
829 
834 int QwtKnob::markerSize() const
835 {
836  return d_data->markerSize;
837 }
838 
842 QSize QwtKnob::sizeHint() const
843 {
844  const QSize hint = qwtKnobSizeHint( this, 50 );
845  return hint.expandedTo( QApplication::globalStrut() );
846 }
847 
853 {
854  return qwtKnobSizeHint( this, 20 );
855 }
int v
virtual void drawMarker(QPainter *, const QRectF &, double arc) const
Draw the marker at the knob&#39;s front.
Definition: qwt_knob.cpp:583
d
void setKnobStyle(KnobStyle)
Set the knob type.
Definition: qwt_knob.cpp:138
int knobWidth() const
double p1() const
void setScale(double lowerBound, double upperBound)
Specify a scale.
Paint a circle in QPalette::ButtonText color.
Definition: qwt_knob.h:107
void setKnobWidth(int)
Change the knob&#39;s width.
Definition: qwt_knob.cpp:768
double p2() const
void setBorderWidth(int bw)
Set the knob&#39;s border width.
Definition: qwt_knob.cpp:799
static void drawFocusRect(QPainter *, const QWidget *)
Draw a focus rectangle on a widget using its style.
#define qFastSin(x)
Definition: qwt_knob.cpp:27
Paint a triangle in QPalette::ButtonText color.
Definition: qwt_knob.h:104
QRect knobRect() const
Definition: qwt_knob.cpp:299
void setAbstractScaleDraw(QwtAbstractScaleDraw *)
Set a scale draw.
int numTurns() const
int transform(double) const
int markerSize
Definition: qwt_knob.h:54
void setValue(double val)
virtual void drawKnob(QPainter *, const QRectF &) const
Draw the knob.
Definition: qwt_knob.cpp:496
The Knob Widget.
Definition: qwt_knob.h:42
static QSize qwtKnobSizeHint(const QwtKnob *knob, int min)
Definition: qwt_knob.cpp:30
void setScaleDraw(QwtRoundScaleDraw *)
Definition: qwt_knob.cpp:266
virtual QSize sizeHint() const
Definition: qwt_knob.cpp:842
Qt::Alignment alignment() const
const QwtScaleMap & scaleMap() const
virtual bool isScrollPosition(const QPoint &) const
Determine what to do when the user presses a mouse button.
Definition: qwt_knob.cpp:354
QwtKnob(QWidget *parent=NULL)
Constructor.
Definition: qwt_knob.cpp:110
static double qwtToDegrees(double value)
Definition: qwt_knob.cpp:60
bool wrapping() const
virtual double extent(const QFont &) const
#define qFastCos(x)
Definition: qwt_knob.cpp:26
MarkerStyle
Marker type.
Definition: qwt_knob.h:95
void setAlignment(Qt::Alignment)
Set the alignment of the knob.
Definition: qwt_knob.cpp:739
Don&#39;t paint any marker.
Definition: qwt_knob.h:98
Qt::Alignment alignment
Definition: qwt_knob.cpp:91
virtual void drawFocusIndicator(QPainter *) const
Definition: qwt_knob.cpp:706
TFSIMD_FORCE_INLINE tfScalar angle(const Quaternion &q1, const Quaternion &q2)
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
void update(const std::string &key, const XmlRpc::XmlRpcValue &v)
An abstract base class for slider widgets with a scale.
double value() const
const QwtRoundScaleDraw * scaleDraw() const
Definition: qwt_knob.cpp:279
int markerSize() const
double qwtRadians(double degrees)
Translate degrees into radians.
Definition: qwt_math.h:144
void setMarkerSize(int)
Set the size of the marker.
Definition: qwt_knob.cpp:821
virtual double scrolledTo(const QPoint &) const
Determine the value for a new position of the mouse.
Definition: qwt_knob.cpp:380
virtual void changeEvent(QEvent *)
Definition: qwt_knob.cpp:438
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 QSize minimumSizeHint() const
Definition: qwt_knob.cpp:852
double invTransform(double p) const
QwtKnob::KnobStyle knobStyle
Definition: qwt_knob.cpp:83
void setAngleRange(double angle1, double angle2)
Adjust the baseline circle segment for round scales.
A class for drawing round scales.
TFSIMD_FORCE_INLINE const tfScalar & w() const
void setTotalAngle(double angle)
Set the total angle by which the knob can be turned.
Definition: qwt_knob.cpp:192
virtual void draw(QPainter *, const QPalette &) const
Draw the scale.
virtual ~QwtKnob()
Destructor.
Definition: qwt_knob.cpp:127
Build a gradient from QPalette::Midlight and QPalette::Button.
Definition: qwt_knob.h:72
static double qwtToScaleAngle(double angle)
Definition: qwt_knob.cpp:46
MarkerStyle markerStyle() const
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:226
double qwtNormalizeDegrees(double degrees)
Normalize an angle to be int the range [0.0, 360.0[.
Definition: qwt_math.cpp:67
virtual void paintEvent(QPaintEvent *)
Definition: qwt_knob.cpp:458
int borderWidth() const
QwtKnob::MarkerStyle markerStyle
Definition: qwt_knob.cpp:84
Fill the knob with a brush from QPalette::Button.
Definition: qwt_knob.h:69
int a
void setMarkerStyle(MarkerStyle)
Set the marker type of the knob.
Definition: qwt_knob.cpp:162


plotjuggler
Author(s): Davide Faconti
autogenerated on Sat Jul 6 2019 03:44:17