00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <qpainter.h>
00011 #include <qpalette.h>
00012 #include <qstyle.h>
00013 #include <qevent.h>
00014 #include "qwt_round_scale_draw.h"
00015 #include "qwt_knob.h"
00016 #include "qwt_math.h"
00017 #include "qwt_painter.h"
00018 #include "qwt_paint_buffer.h"
00019
00020 class QwtKnob::PrivateData
00021 {
00022 public:
00023 PrivateData()
00024 {
00025 angle = 0.0;
00026 nTurns = 0.0;
00027 borderWidth = 2;
00028 borderDist = 4;
00029 totalAngle = 270.0;
00030 scaleDist = 4;
00031 symbol = Line;
00032 maxScaleTicks = 11;
00033 knobWidth = 50;
00034 dotWidth = 8;
00035 }
00036
00037 int borderWidth;
00038 int borderDist;
00039 int scaleDist;
00040 int maxScaleTicks;
00041 int knobWidth;
00042 int dotWidth;
00043
00044 Symbol symbol;
00045 double angle;
00046 double totalAngle;
00047 double nTurns;
00048
00049 QRect knobRect;
00050 };
00051
00056 QwtKnob::QwtKnob(QWidget* parent):
00057 QwtAbstractSlider(Qt::Horizontal, parent)
00058 {
00059 initKnob();
00060 }
00061
00062 #if QT_VERSION < 0x040000
00063
00068 QwtKnob::QwtKnob(QWidget* parent, const char *name):
00069 QwtAbstractSlider(Qt::Horizontal, parent)
00070 {
00071 setName(name);
00072 initKnob();
00073 }
00074 #endif
00075
00076 void QwtKnob::initKnob()
00077 {
00078 #if QT_VERSION < 0x040000
00079 setWFlags(Qt::WNoAutoErase);
00080 #endif
00081
00082 d_data = new PrivateData;
00083
00084 setScaleDraw(new QwtRoundScaleDraw());
00085
00086 setUpdateTime(50);
00087 setTotalAngle( 270.0 );
00088 recalcAngle();
00089 setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
00090
00091 setRange(0.0, 10.0, 1.0);
00092 setValue(0.0);
00093 }
00094
00096 QwtKnob::~QwtKnob()
00097 {
00098 delete d_data;
00099 }
00100
00105 void QwtKnob::setSymbol(QwtKnob::Symbol s)
00106 {
00107 if ( d_data->symbol != s )
00108 {
00109 d_data->symbol = s;
00110 update();
00111 }
00112 }
00113
00118 QwtKnob::Symbol QwtKnob::symbol() const
00119 {
00120 return d_data->symbol;
00121 }
00122
00131 void QwtKnob::setTotalAngle (double angle)
00132 {
00133 if (angle < 10.0)
00134 d_data->totalAngle = 10.0;
00135 else
00136 d_data->totalAngle = angle;
00137
00138 scaleDraw()->setAngleRange( -0.5 * d_data->totalAngle,
00139 0.5 * d_data->totalAngle);
00140 layoutKnob();
00141 }
00142
00144 double QwtKnob::totalAngle() const
00145 {
00146 return d_data->totalAngle;
00147 }
00148
00158 void QwtKnob::setScaleDraw(QwtRoundScaleDraw *scaleDraw)
00159 {
00160 setAbstractScaleDraw(scaleDraw);
00161 setTotalAngle(d_data->totalAngle);
00162 }
00163
00168 const QwtRoundScaleDraw *QwtKnob::scaleDraw() const
00169 {
00170 return (QwtRoundScaleDraw *)abstractScaleDraw();
00171 }
00172
00177 QwtRoundScaleDraw *QwtKnob::scaleDraw()
00178 {
00179 return (QwtRoundScaleDraw *)abstractScaleDraw();
00180 }
00181
00187 void QwtKnob::drawKnob(QPainter *painter, const QRect &r)
00188 {
00189 #if QT_VERSION < 0x040000
00190 const QBrush buttonBrush = colorGroup().brush(QColorGroup::Button);
00191 const QColor buttonTextColor = colorGroup().buttonText();
00192 const QColor lightColor = colorGroup().light();
00193 const QColor darkColor = colorGroup().dark();
00194 #else
00195 const QBrush buttonBrush = palette().brush(QPalette::Button);
00196 const QColor buttonTextColor = palette().color(QPalette::ButtonText);
00197 const QColor lightColor = palette().color(QPalette::Light);
00198 const QColor darkColor = palette().color(QPalette::Dark);
00199 #endif
00200
00201 const int bw2 = d_data->borderWidth / 2;
00202
00203 const int radius = (qwtMin(r.width(), r.height()) - bw2) / 2;
00204
00205 const QRect aRect(
00206 r.center().x() - radius, r.center().y() - radius,
00207 2 * radius, 2 * radius);
00208
00209
00210
00211
00212 painter->setBrush(buttonBrush);
00213 painter->drawEllipse(aRect);
00214
00215
00216
00217
00218 QPen pn;
00219 pn.setWidth(d_data->borderWidth);
00220
00221 pn.setColor(lightColor);
00222 painter->setPen(pn);
00223 painter->drawArc(aRect, 45*16, 180*16);
00224
00225 pn.setColor(darkColor);
00226 painter->setPen(pn);
00227 painter->drawArc(aRect, 225*16, 180*16);
00228
00229
00230
00231
00232 if ( isValid() )
00233 drawMarker(painter, d_data->angle, buttonTextColor);
00234 }
00235
00242 void QwtKnob::valueChange()
00243 {
00244 recalcAngle();
00245 update();
00246 QwtAbstractSlider::valueChange();
00247 }
00248
00255 double QwtKnob::getValue(const QPoint &p)
00256 {
00257 const double dx = double((rect().x() + rect().width() / 2) - p.x() );
00258 const double dy = double((rect().y() + rect().height() / 2) - p.y() );
00259
00260 const double arc = atan2(-dx,dy) * 180.0 / M_PI;
00261
00262 double newValue = 0.5 * (minValue() + maxValue())
00263 + (arc + d_data->nTurns * 360.0) * (maxValue() - minValue())
00264 / d_data->totalAngle;
00265
00266 const double oneTurn = fabs(maxValue() - minValue()) * 360.0 / d_data->totalAngle;
00267 const double eqValue = value() + mouseOffset();
00268
00269 if (fabs(newValue - eqValue) > 0.5 * oneTurn)
00270 {
00271 if (newValue < eqValue)
00272 newValue += oneTurn;
00273 else
00274 newValue -= oneTurn;
00275 }
00276
00277 return newValue;
00278 }
00279
00286 void QwtKnob::getScrollMode(const QPoint &p, int &scrollMode, int &direction)
00287 {
00288 const int r = d_data->knobRect.width() / 2;
00289
00290 const int dx = d_data->knobRect.x() + r - p.x();
00291 const int dy = d_data->knobRect.y() + r - p.y();
00292
00293 if ( (dx * dx) + (dy * dy) <= (r * r))
00294 {
00295 scrollMode = ScrMouse;
00296 direction = 0;
00297 }
00298 else
00299 {
00300 scrollMode = ScrTimer;
00301 double arc = atan2(double(-dx),double(dy)) * 180.0 / M_PI;
00302 if ( arc < d_data->angle)
00303 direction = -1;
00304 else if (arc > d_data->angle)
00305 direction = 1;
00306 else
00307 direction = 0;
00308 }
00309 }
00310
00311
00317 void QwtKnob::rangeChange()
00318 {
00319 if (autoScale())
00320 rescale(minValue(), maxValue());
00321
00322 layoutKnob();
00323 recalcAngle();
00324 }
00325
00329 void QwtKnob::resizeEvent(QResizeEvent *)
00330 {
00331 layoutKnob( false );
00332 }
00333
00341 void QwtKnob::layoutKnob( bool update_geometry )
00342 {
00343 const QRect r = rect();
00344 const int radius = d_data->knobWidth / 2;
00345
00346 d_data->knobRect.setWidth(2 * radius);
00347 d_data->knobRect.setHeight(2 * radius);
00348 d_data->knobRect.moveCenter(r.center());
00349
00350 scaleDraw()->setRadius(radius + d_data->scaleDist);
00351 scaleDraw()->moveCenter(r.center());
00352
00353 if ( update_geometry )
00354 {
00355 updateGeometry();
00356 update();
00357 }
00358 }
00359
00365 void QwtKnob::paintEvent(QPaintEvent *e)
00366 {
00367 const QRect &ur = e->rect();
00368 if ( ur.isValid() )
00369 {
00370 #if QT_VERSION < 0x040000
00371 QwtPaintBuffer paintBuffer(this, ur);
00372 draw(paintBuffer.painter(), ur);
00373 #else
00374 QPainter painter(this);
00375 painter.setRenderHint(QPainter::Antialiasing);
00376 draw(&painter, ur);
00377 #endif
00378 }
00379 }
00380
00387 void QwtKnob::draw(QPainter *painter, const QRect& rect)
00388 {
00389 if ( !d_data->knobRect.contains( rect ) )
00390 {
00391 #if QT_VERSION < 0x040000
00392 scaleDraw()->draw( painter, colorGroup() );
00393 #else
00394 scaleDraw()->draw( painter, palette() );
00395 #endif
00396 }
00397
00398 drawKnob( painter, d_data->knobRect );
00399
00400 if ( hasFocus() )
00401 QwtPainter::drawFocusRect(painter, this);
00402 }
00403
00410 void QwtKnob::drawMarker(QPainter *p, double arc, const QColor &c)
00411 {
00412 const double rarc = arc * M_PI / 180.0;
00413 const double ca = cos(rarc);
00414 const double sa = - sin(rarc);
00415
00416 int radius = d_data->knobRect.width() / 2 - d_data->borderWidth;
00417 if (radius < 3)
00418 radius = 3;
00419
00420 const int ym = d_data->knobRect.y() + radius + d_data->borderWidth;
00421 const int xm = d_data->knobRect.x() + radius + d_data->borderWidth;
00422
00423 switch (d_data->symbol)
00424 {
00425 case Dot:
00426 {
00427 p->setBrush(c);
00428 p->setPen(Qt::NoPen);
00429
00430 const double rb = double(qwtMax(radius - 4 - d_data->dotWidth / 2, 0));
00431 p->drawEllipse(xm - qRound(sa * rb) - d_data->dotWidth / 2,
00432 ym - qRound(ca * rb) - d_data->dotWidth / 2,
00433 d_data->dotWidth, d_data->dotWidth);
00434 break;
00435 }
00436 case Line:
00437 {
00438 p->setPen(QPen(c, 2));
00439
00440 const double rb = qwtMax(double((radius - 4) / 3.0), 0.0);
00441 const double re = qwtMax(double(radius - 4), 0.0);
00442
00443 p->drawLine ( xm - qRound(sa * rb), ym - qRound(ca * rb),
00444 xm - qRound(sa * re), ym - qRound(ca * re));
00445
00446 break;
00447 }
00448 }
00449 }
00450
00457 void QwtKnob::setKnobWidth(int w)
00458 {
00459 d_data->knobWidth = qwtMax(w,5);
00460 layoutKnob();
00461 }
00462
00464 int QwtKnob::knobWidth() const
00465 {
00466 return d_data->knobWidth;
00467 }
00468
00473 void QwtKnob::setBorderWidth(int bw)
00474 {
00475 d_data->borderWidth = qwtMax(bw, 0);
00476 layoutKnob();
00477 }
00478
00480 int QwtKnob::borderWidth() const
00481 {
00482 return d_data->borderWidth;
00483 }
00484
00489 void QwtKnob::recalcAngle()
00490 {
00491
00492
00493
00494 if (maxValue() == minValue())
00495 {
00496 d_data->angle = 0;
00497 d_data->nTurns = 0;
00498 }
00499 else
00500 {
00501 d_data->angle = (value() - 0.5 * (minValue() + maxValue()))
00502 / (maxValue() - minValue()) * d_data->totalAngle;
00503 d_data->nTurns = floor((d_data->angle + 180.0) / 360.0);
00504 d_data->angle = d_data->angle - d_data->nTurns * 360.0;
00505 }
00506 }
00507
00508
00513 void QwtKnob::scaleChange()
00514 {
00515 layoutKnob();
00516 }
00517
00522 void QwtKnob::fontChange(const QFont &f)
00523 {
00524 QwtAbstractSlider::fontChange( f );
00525 layoutKnob();
00526 }
00527
00531 QSize QwtKnob::sizeHint() const
00532 {
00533 return minimumSizeHint();
00534 }
00535
00541 QSize QwtKnob::minimumSizeHint() const
00542 {
00543
00544 const int sh = scaleDraw()->extent( QPen(), font() );
00545 const int d = 2 * sh + 2 * d_data->scaleDist + d_data->knobWidth;
00546
00547 return QSize( d, d );
00548 }