00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <qpainter.h>
00011 #if QT_VERSION >= 0x040000
00012 #include <qpaintengine.h>
00013 #endif
00014 #include <qpalette.h>
00015 #include <qstyle.h>
00016 #include <qevent.h>
00017 #include "qwt_round_scale_draw.h"
00018 #include "qwt_knob.h"
00019 #include "qwt_math.h"
00020 #include "qwt_painter.h"
00021 #include "qwt_paint_buffer.h"
00022
00023 class QwtKnob::PrivateData
00024 {
00025 public:
00026 PrivateData()
00027 {
00028 angle = 0.0;
00029 nTurns = 0.0;
00030 borderWidth = 2;
00031 borderDist = 4;
00032 totalAngle = 270.0;
00033 scaleDist = 4;
00034 symbol = Line;
00035 maxScaleTicks = 11;
00036 knobWidth = 50;
00037 dotWidth = 8;
00038 }
00039
00040 int borderWidth;
00041 int borderDist;
00042 int scaleDist;
00043 int maxScaleTicks;
00044 int knobWidth;
00045 int dotWidth;
00046
00047 Symbol symbol;
00048 double angle;
00049 double totalAngle;
00050 double nTurns;
00051
00052 QRect knobRect;
00053 };
00054
00059 QwtKnob::QwtKnob(QWidget* parent):
00060 QwtAbstractSlider(Qt::Horizontal, parent)
00061 {
00062 #if QT_VERSION < 0x040000
00063 setWFlags(Qt::WNoAutoErase);
00064 #endif
00065
00066 d_data = new PrivateData;
00067
00068 setScaleDraw(new QwtRoundScaleDraw());
00069
00070 setUpdateTime(50);
00071 setTotalAngle( 270.0 );
00072 recalcAngle();
00073 setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
00074
00075 setRange(0.0, 10.0, 1.0);
00076 setValue(0.0);
00077 }
00078
00080 QwtKnob::~QwtKnob()
00081 {
00082 delete d_data;
00083 }
00084
00089 void QwtKnob::setSymbol(QwtKnob::Symbol s)
00090 {
00091 if ( d_data->symbol != s )
00092 {
00093 d_data->symbol = s;
00094 update();
00095 }
00096 }
00097
00102 QwtKnob::Symbol QwtKnob::symbol() const
00103 {
00104 return d_data->symbol;
00105 }
00106
00115 void QwtKnob::setTotalAngle (double angle)
00116 {
00117 if (angle < 10.0)
00118 d_data->totalAngle = 10.0;
00119 else
00120 d_data->totalAngle = angle;
00121
00122 scaleDraw()->setAngleRange( -0.5 * d_data->totalAngle,
00123 0.5 * d_data->totalAngle);
00124 layoutKnob();
00125 }
00126
00128 double QwtKnob::totalAngle() const
00129 {
00130 return d_data->totalAngle;
00131 }
00132
00142 void QwtKnob::setScaleDraw(QwtRoundScaleDraw *scaleDraw)
00143 {
00144 setAbstractScaleDraw(scaleDraw);
00145 }
00146
00151 const QwtRoundScaleDraw *QwtKnob::scaleDraw() const
00152 {
00153 return (QwtRoundScaleDraw *)abstractScaleDraw();
00154 }
00155
00160 QwtRoundScaleDraw *QwtKnob::scaleDraw()
00161 {
00162 return (QwtRoundScaleDraw *)abstractScaleDraw();
00163 }
00164
00170 void QwtKnob::drawKnob(QPainter *painter, const QRect &r)
00171 {
00172 #if QT_VERSION < 0x040000
00173 const QBrush buttonBrush = colorGroup().brush(QColorGroup::Button);
00174 const QColor buttonTextColor = colorGroup().buttonText();
00175 const QColor lightColor = colorGroup().light();
00176 const QColor darkColor = colorGroup().dark();
00177 #else
00178 const QBrush buttonBrush = palette().brush(QPalette::Button);
00179 const QColor buttonTextColor = palette().color(QPalette::ButtonText);
00180 const QColor lightColor = palette().color(QPalette::Light);
00181 const QColor darkColor = palette().color(QPalette::Dark);
00182 #endif
00183
00184 const int bw2 = d_data->borderWidth / 2;
00185
00186 const int radius = (qwtMin(r.width(), r.height()) - bw2) / 2;
00187
00188 const QRect aRect(
00189 r.center().x() - radius, r.center().y() - radius,
00190 2 * radius, 2 * radius);
00191
00192
00193
00194
00195 painter->setBrush(buttonBrush);
00196 painter->drawEllipse(aRect);
00197
00198
00199
00200
00201 QPen pn;
00202 pn.setWidth(d_data->borderWidth);
00203
00204 pn.setColor(lightColor);
00205 painter->setPen(pn);
00206 painter->drawArc(aRect, 45*16, 180*16);
00207
00208 pn.setColor(darkColor);
00209 painter->setPen(pn);
00210 painter->drawArc(aRect, 225*16, 180*16);
00211
00212
00213
00214
00215 if ( isValid() )
00216 drawMarker(painter, d_data->angle, buttonTextColor);
00217 }
00218
00225 void QwtKnob::valueChange()
00226 {
00227 recalcAngle();
00228 update();
00229 QwtAbstractSlider::valueChange();
00230 }
00231
00238 double QwtKnob::getValue(const QPoint &p)
00239 {
00240 const double dx = double((rect().x() + rect().width() / 2) - p.x() );
00241 const double dy = double((rect().y() + rect().height() / 2) - p.y() );
00242
00243 const double arc = atan2(-dx,dy) * 180.0 / M_PI;
00244
00245 double newValue = 0.5 * (minValue() + maxValue())
00246 + (arc + d_data->nTurns * 360.0) * (maxValue() - minValue())
00247 / d_data->totalAngle;
00248
00249 const double oneTurn = fabs(maxValue() - minValue()) * 360.0 / d_data->totalAngle;
00250 const double eqValue = value() + mouseOffset();
00251
00252 if (fabs(newValue - eqValue) > 0.5 * oneTurn)
00253 {
00254 if (newValue < eqValue)
00255 newValue += oneTurn;
00256 else
00257 newValue -= oneTurn;
00258 }
00259
00260 return newValue;
00261 }
00262
00269 void QwtKnob::getScrollMode(const QPoint &p, int &scrollMode, int &direction)
00270 {
00271 const int r = d_data->knobRect.width() / 2;
00272
00273 const int dx = d_data->knobRect.x() + r - p.x();
00274 const int dy = d_data->knobRect.y() + r - p.y();
00275
00276 if ( (dx * dx) + (dy * dy) <= (r * r))
00277 {
00278 scrollMode = ScrMouse;
00279 direction = 0;
00280 }
00281 else
00282 {
00283 scrollMode = ScrTimer;
00284 double arc = atan2(double(-dx),double(dy)) * 180.0 / M_PI;
00285 if ( arc < d_data->angle)
00286 direction = -1;
00287 else if (arc > d_data->angle)
00288 direction = 1;
00289 else
00290 direction = 0;
00291 }
00292 }
00293
00294
00300 void QwtKnob::rangeChange()
00301 {
00302 if (autoScale())
00303 rescale(minValue(), maxValue());
00304
00305 layoutKnob();
00306 recalcAngle();
00307 }
00308
00312 void QwtKnob::resizeEvent(QResizeEvent *)
00313 {
00314 layoutKnob( false );
00315 }
00316
00318
00319
00320
00321 void QwtKnob::layoutKnob( bool update_geometry )
00322 {
00323 const QRect r = rect();
00324 const int radius = d_data->knobWidth / 2;
00325
00326 d_data->knobRect.setWidth(2 * radius);
00327 d_data->knobRect.setHeight(2 * radius);
00328 d_data->knobRect.moveCenter(r.center());
00329
00330 scaleDraw()->setRadius(radius + d_data->scaleDist);
00331 scaleDraw()->moveCenter(r.center());
00332
00333 if ( update_geometry )
00334 {
00335 updateGeometry();
00336 update();
00337 }
00338 }
00339
00343 void QwtKnob::paintEvent(QPaintEvent *e)
00344 {
00345 const QRect &ur = e->rect();
00346 if ( ur.isValid() )
00347 {
00348 #if QT_VERSION < 0x040000
00349 QwtPaintBuffer paintBuffer(this, ur);
00350 draw(paintBuffer.painter(), ur);
00351 #else
00352 QPainter painter(this);
00353 if ( paintEngine()->hasFeature(QPaintEngine::Antialiasing) )
00354 painter.setRenderHint(QPainter::Antialiasing);
00355 draw(&painter, ur);
00356 #endif
00357 }
00358 }
00359
00363 void QwtKnob::draw(QPainter *painter, const QRect& ur)
00364 {
00365 if ( !d_data->knobRect.contains( ur ) )
00366 {
00367 #if QT_VERSION < 0x040000
00368 scaleDraw()->draw( painter, colorGroup() );
00369 #else
00370 scaleDraw()->draw( painter, palette() );
00371 #endif
00372 }
00373
00374 drawKnob( painter, d_data->knobRect );
00375
00376 if ( hasFocus() )
00377 QwtPainter::drawFocusRect(painter, this);
00378 }
00379
00386 void QwtKnob::drawMarker(QPainter *p, double arc, const QColor &c)
00387 {
00388 const double rarc = arc * M_PI / 180.0;
00389 const double ca = cos(rarc);
00390 const double sa = - sin(rarc);
00391
00392 int radius = d_data->knobRect.width() / 2 - d_data->borderWidth;
00393 if (radius < 3)
00394 radius = 3;
00395
00396 const int ym = d_data->knobRect.y() + radius + d_data->borderWidth;
00397 const int xm = d_data->knobRect.x() + radius + d_data->borderWidth;
00398
00399 switch (d_data->symbol)
00400 {
00401 case Dot:
00402 {
00403 p->setBrush(c);
00404 p->setPen(Qt::NoPen);
00405
00406 const double rb = double(qwtMax(radius - 4 - d_data->dotWidth / 2, 0));
00407 p->drawEllipse(xm - qRound(sa * rb) - d_data->dotWidth / 2,
00408 ym - qRound(ca * rb) - d_data->dotWidth / 2,
00409 d_data->dotWidth, d_data->dotWidth);
00410 break;
00411 }
00412 case Line:
00413 {
00414 p->setPen(QPen(c, 2));
00415
00416 const double rb = qwtMax(double((radius - 4) / 3.0), 0.0);
00417 const double re = qwtMax(double(radius - 4), 0.0);
00418
00419 p->drawLine ( xm - qRound(sa * rb), ym - qRound(ca * rb),
00420 xm - qRound(sa * re), ym - qRound(ca * re));
00421
00422 break;
00423 }
00424 }
00425 }
00426
00433 void QwtKnob::setKnobWidth(int w)
00434 {
00435 d_data->knobWidth = qwtMax(w,5);
00436 layoutKnob();
00437 }
00438
00440 int QwtKnob::knobWidth() const
00441 {
00442 return d_data->knobWidth;
00443 }
00444
00449 void QwtKnob::setBorderWidth(int bw)
00450 {
00451 d_data->borderWidth = qwtMax(bw, 0);
00452 layoutKnob();
00453 }
00454
00456 int QwtKnob::borderWidth() const
00457 {
00458 return d_data->borderWidth;
00459 }
00460
00465 void QwtKnob::recalcAngle()
00466 {
00467
00468
00469
00470 if (maxValue() == minValue())
00471 {
00472 d_data->angle = 0;
00473 d_data->nTurns = 0;
00474 }
00475 else
00476 {
00477 d_data->angle = (value() - 0.5 * (minValue() + maxValue()))
00478 / (maxValue() - minValue()) * d_data->totalAngle;
00479 d_data->nTurns = floor((d_data->angle + 180.0) / 360.0);
00480 d_data->angle = d_data->angle - d_data->nTurns * 360.0;
00481 }
00482 }
00483
00484
00489 void QwtKnob::scaleChange()
00490 {
00491 layoutKnob();
00492 }
00493
00498 void QwtKnob::fontChange(const QFont &f)
00499 {
00500 QwtAbstractSlider::fontChange( f );
00501 layoutKnob();
00502 }
00503
00507 QSize QwtKnob::sizeHint() const
00508 {
00509 return minimumSizeHint();
00510 }
00511
00517 QSize QwtKnob::minimumSizeHint() const
00518 {
00519
00520 const int sh = scaleDraw()->extent( QPen(), font() );
00521 const int d = 2 * sh + 2 * d_data->scaleDist + d_data->knobWidth;
00522
00523 return QSize( d, d );
00524 }