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 initKnob();
00063 }
00064
00065 #if QT_VERSION < 0x040000
00066
00071 QwtKnob::QwtKnob(QWidget* parent, const char *name):
00072 QwtAbstractSlider(Qt::Horizontal, parent)
00073 {
00074 setName(name);
00075 initKnob();
00076 }
00077 #endif
00078
00079 void QwtKnob::initKnob()
00080 {
00081 #if QT_VERSION < 0x040000
00082 setWFlags(Qt::WNoAutoErase);
00083 #endif
00084
00085 d_data = new PrivateData;
00086
00087 setScaleDraw(new QwtRoundScaleDraw());
00088
00089 setUpdateTime(50);
00090 setTotalAngle( 270.0 );
00091 recalcAngle();
00092 setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
00093
00094 setRange(0.0, 10.0, 1.0);
00095 setValue(0.0);
00096 }
00097
00099 QwtKnob::~QwtKnob()
00100 {
00101 delete d_data;
00102 }
00103
00108 void QwtKnob::setSymbol(QwtKnob::Symbol s)
00109 {
00110 if ( d_data->symbol != s )
00111 {
00112 d_data->symbol = s;
00113 update();
00114 }
00115 }
00116
00121 QwtKnob::Symbol QwtKnob::symbol() const
00122 {
00123 return d_data->symbol;
00124 }
00125
00134 void QwtKnob::setTotalAngle (double angle)
00135 {
00136 if (angle < 10.0)
00137 d_data->totalAngle = 10.0;
00138 else
00139 d_data->totalAngle = angle;
00140
00141 scaleDraw()->setAngleRange( -0.5 * d_data->totalAngle,
00142 0.5 * d_data->totalAngle);
00143 layoutKnob();
00144 }
00145
00147 double QwtKnob::totalAngle() const
00148 {
00149 return d_data->totalAngle;
00150 }
00151
00161 void QwtKnob::setScaleDraw(QwtRoundScaleDraw *scaleDraw)
00162 {
00163 setAbstractScaleDraw(scaleDraw);
00164 setTotalAngle(d_data->totalAngle);
00165 }
00166
00171 const QwtRoundScaleDraw *QwtKnob::scaleDraw() const
00172 {
00173 return (QwtRoundScaleDraw *)abstractScaleDraw();
00174 }
00175
00180 QwtRoundScaleDraw *QwtKnob::scaleDraw()
00181 {
00182 return (QwtRoundScaleDraw *)abstractScaleDraw();
00183 }
00184
00190 void QwtKnob::drawKnob(QPainter *painter, const QRect &r)
00191 {
00192 #if QT_VERSION < 0x040000
00193 const QBrush buttonBrush = colorGroup().brush(QColorGroup::Button);
00194 const QColor buttonTextColor = colorGroup().buttonText();
00195 const QColor lightColor = colorGroup().light();
00196 const QColor darkColor = colorGroup().dark();
00197 #else
00198 const QBrush buttonBrush = palette().brush(QPalette::Button);
00199 const QColor buttonTextColor = palette().color(QPalette::ButtonText);
00200 const QColor lightColor = palette().color(QPalette::Light);
00201 const QColor darkColor = palette().color(QPalette::Dark);
00202 #endif
00203
00204 const int bw2 = d_data->borderWidth / 2;
00205
00206 const int radius = (qwtMin(r.width(), r.height()) - bw2) / 2;
00207
00208 const QRect aRect(
00209 r.center().x() - radius, r.center().y() - radius,
00210 2 * radius, 2 * radius);
00211
00212
00213
00214
00215 painter->setBrush(buttonBrush);
00216 painter->drawEllipse(aRect);
00217
00218
00219
00220
00221 QPen pn;
00222 pn.setWidth(d_data->borderWidth);
00223
00224 pn.setColor(lightColor);
00225 painter->setPen(pn);
00226 painter->drawArc(aRect, 45*16, 180*16);
00227
00228 pn.setColor(darkColor);
00229 painter->setPen(pn);
00230 painter->drawArc(aRect, 225*16, 180*16);
00231
00232
00233
00234
00235 if ( isValid() )
00236 drawMarker(painter, d_data->angle, buttonTextColor);
00237 }
00238
00245 void QwtKnob::valueChange()
00246 {
00247 recalcAngle();
00248 update();
00249 QwtAbstractSlider::valueChange();
00250 }
00251
00258 double QwtKnob::getValue(const QPoint &p)
00259 {
00260 const double dx = double((rect().x() + rect().width() / 2) - p.x() );
00261 const double dy = double((rect().y() + rect().height() / 2) - p.y() );
00262
00263 const double arc = atan2(-dx,dy) * 180.0 / M_PI;
00264
00265 double newValue = 0.5 * (minValue() + maxValue())
00266 + (arc + d_data->nTurns * 360.0) * (maxValue() - minValue())
00267 / d_data->totalAngle;
00268
00269 const double oneTurn = fabs(maxValue() - minValue()) * 360.0 / d_data->totalAngle;
00270 const double eqValue = value() + mouseOffset();
00271
00272 if (fabs(newValue - eqValue) > 0.5 * oneTurn)
00273 {
00274 if (newValue < eqValue)
00275 newValue += oneTurn;
00276 else
00277 newValue -= oneTurn;
00278 }
00279
00280 return newValue;
00281 }
00282
00289 void QwtKnob::getScrollMode(const QPoint &p, int &scrollMode, int &direction)
00290 {
00291 const int r = d_data->knobRect.width() / 2;
00292
00293 const int dx = d_data->knobRect.x() + r - p.x();
00294 const int dy = d_data->knobRect.y() + r - p.y();
00295
00296 if ( (dx * dx) + (dy * dy) <= (r * r))
00297 {
00298 scrollMode = ScrMouse;
00299 direction = 0;
00300 }
00301 else
00302 {
00303 scrollMode = ScrTimer;
00304 double arc = atan2(double(-dx),double(dy)) * 180.0 / M_PI;
00305 if ( arc < d_data->angle)
00306 direction = -1;
00307 else if (arc > d_data->angle)
00308 direction = 1;
00309 else
00310 direction = 0;
00311 }
00312 }
00313
00314
00320 void QwtKnob::rangeChange()
00321 {
00322 if (autoScale())
00323 rescale(minValue(), maxValue());
00324
00325 layoutKnob();
00326 recalcAngle();
00327 }
00328
00332 void QwtKnob::resizeEvent(QResizeEvent *)
00333 {
00334 layoutKnob( false );
00335 }
00336
00338
00339
00340
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
00363 void QwtKnob::paintEvent(QPaintEvent *e)
00364 {
00365 const QRect &ur = e->rect();
00366 if ( ur.isValid() )
00367 {
00368 #if QT_VERSION < 0x040000
00369 QwtPaintBuffer paintBuffer(this, ur);
00370 draw(paintBuffer.painter(), ur);
00371 #else
00372 QPainter painter(this);
00373 if ( paintEngine()->hasFeature(QPaintEngine::Antialiasing) )
00374 painter.setRenderHint(QPainter::Antialiasing);
00375 draw(&painter, ur);
00376 #endif
00377 }
00378 }
00379
00383 void QwtKnob::draw(QPainter *painter, const QRect& ur)
00384 {
00385 if ( !d_data->knobRect.contains( ur ) )
00386 {
00387 #if QT_VERSION < 0x040000
00388 scaleDraw()->draw( painter, colorGroup() );
00389 #else
00390 scaleDraw()->draw( painter, palette() );
00391 #endif
00392 }
00393
00394 drawKnob( painter, d_data->knobRect );
00395
00396 if ( hasFocus() )
00397 QwtPainter::drawFocusRect(painter, this);
00398 }
00399
00406 void QwtKnob::drawMarker(QPainter *p, double arc, const QColor &c)
00407 {
00408 const double rarc = arc * M_PI / 180.0;
00409 const double ca = cos(rarc);
00410 const double sa = - sin(rarc);
00411
00412 int radius = d_data->knobRect.width() / 2 - d_data->borderWidth;
00413 if (radius < 3)
00414 radius = 3;
00415
00416 const int ym = d_data->knobRect.y() + radius + d_data->borderWidth;
00417 const int xm = d_data->knobRect.x() + radius + d_data->borderWidth;
00418
00419 switch (d_data->symbol)
00420 {
00421 case Dot:
00422 {
00423 p->setBrush(c);
00424 p->setPen(Qt::NoPen);
00425
00426 const double rb = double(qwtMax(radius - 4 - d_data->dotWidth / 2, 0));
00427 p->drawEllipse(xm - qRound(sa * rb) - d_data->dotWidth / 2,
00428 ym - qRound(ca * rb) - d_data->dotWidth / 2,
00429 d_data->dotWidth, d_data->dotWidth);
00430 break;
00431 }
00432 case Line:
00433 {
00434 p->setPen(QPen(c, 2));
00435
00436 const double rb = qwtMax(double((radius - 4) / 3.0), 0.0);
00437 const double re = qwtMax(double(radius - 4), 0.0);
00438
00439 p->drawLine ( xm - qRound(sa * rb), ym - qRound(ca * rb),
00440 xm - qRound(sa * re), ym - qRound(ca * re));
00441
00442 break;
00443 }
00444 }
00445 }
00446
00453 void QwtKnob::setKnobWidth(int w)
00454 {
00455 d_data->knobWidth = qwtMax(w,5);
00456 layoutKnob();
00457 }
00458
00460 int QwtKnob::knobWidth() const
00461 {
00462 return d_data->knobWidth;
00463 }
00464
00469 void QwtKnob::setBorderWidth(int bw)
00470 {
00471 d_data->borderWidth = qwtMax(bw, 0);
00472 layoutKnob();
00473 }
00474
00476 int QwtKnob::borderWidth() const
00477 {
00478 return d_data->borderWidth;
00479 }
00480
00485 void QwtKnob::recalcAngle()
00486 {
00487
00488
00489
00490 if (maxValue() == minValue())
00491 {
00492 d_data->angle = 0;
00493 d_data->nTurns = 0;
00494 }
00495 else
00496 {
00497 d_data->angle = (value() - 0.5 * (minValue() + maxValue()))
00498 / (maxValue() - minValue()) * d_data->totalAngle;
00499 d_data->nTurns = floor((d_data->angle + 180.0) / 360.0);
00500 d_data->angle = d_data->angle - d_data->nTurns * 360.0;
00501 }
00502 }
00503
00504
00509 void QwtKnob::scaleChange()
00510 {
00511 layoutKnob();
00512 }
00513
00518 void QwtKnob::fontChange(const QFont &f)
00519 {
00520 QwtAbstractSlider::fontChange( f );
00521 layoutKnob();
00522 }
00523
00527 QSize QwtKnob::sizeHint() const
00528 {
00529 return minimumSizeHint();
00530 }
00531
00537 QSize QwtKnob::minimumSizeHint() const
00538 {
00539
00540 const int sh = scaleDraw()->extent( QPen(), font() );
00541 const int d = 2 * sh + 2 * d_data->scaleDist + d_data->knobWidth;
00542
00543 return QSize( d, d );
00544 }