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 }
00165
00170 const QwtRoundScaleDraw *QwtKnob::scaleDraw() const
00171 {
00172 return (QwtRoundScaleDraw *)abstractScaleDraw();
00173 }
00174
00179 QwtRoundScaleDraw *QwtKnob::scaleDraw()
00180 {
00181 return (QwtRoundScaleDraw *)abstractScaleDraw();
00182 }
00183
00189 void QwtKnob::drawKnob(QPainter *painter, const QRect &r)
00190 {
00191 #if QT_VERSION < 0x040000
00192 const QBrush buttonBrush = colorGroup().brush(QColorGroup::Button);
00193 const QColor buttonTextColor = colorGroup().buttonText();
00194 const QColor lightColor = colorGroup().light();
00195 const QColor darkColor = colorGroup().dark();
00196 #else
00197 const QBrush buttonBrush = palette().brush(QPalette::Button);
00198 const QColor buttonTextColor = palette().color(QPalette::ButtonText);
00199 const QColor lightColor = palette().color(QPalette::Light);
00200 const QColor darkColor = palette().color(QPalette::Dark);
00201 #endif
00202
00203 const int bw2 = d_data->borderWidth / 2;
00204
00205 const int radius = (qwtMin(r.width(), r.height()) - bw2) / 2;
00206
00207 const QRect aRect(
00208 r.center().x() - radius, r.center().y() - radius,
00209 2 * radius, 2 * radius);
00210
00211
00212
00213
00214 painter->setBrush(buttonBrush);
00215 painter->drawEllipse(aRect);
00216
00217
00218
00219
00220 QPen pn;
00221 pn.setWidth(d_data->borderWidth);
00222
00223 pn.setColor(lightColor);
00224 painter->setPen(pn);
00225 painter->drawArc(aRect, 45*16, 180*16);
00226
00227 pn.setColor(darkColor);
00228 painter->setPen(pn);
00229 painter->drawArc(aRect, 225*16, 180*16);
00230
00231
00232
00233
00234 if ( isValid() )
00235 drawMarker(painter, d_data->angle, buttonTextColor);
00236 }
00237
00244 void QwtKnob::valueChange()
00245 {
00246 recalcAngle();
00247 update();
00248 QwtAbstractSlider::valueChange();
00249 }
00250
00257 double QwtKnob::getValue(const QPoint &p)
00258 {
00259 const double dx = double((rect().x() + rect().width() / 2) - p.x() );
00260 const double dy = double((rect().y() + rect().height() / 2) - p.y() );
00261
00262 const double arc = atan2(-dx,dy) * 180.0 / M_PI;
00263
00264 double newValue = 0.5 * (minValue() + maxValue())
00265 + (arc + d_data->nTurns * 360.0) * (maxValue() - minValue())
00266 / d_data->totalAngle;
00267
00268 const double oneTurn = fabs(maxValue() - minValue()) * 360.0 / d_data->totalAngle;
00269 const double eqValue = value() + mouseOffset();
00270
00271 if (fabs(newValue - eqValue) > 0.5 * oneTurn)
00272 {
00273 if (newValue < eqValue)
00274 newValue += oneTurn;
00275 else
00276 newValue -= oneTurn;
00277 }
00278
00279 return newValue;
00280 }
00281
00288 void QwtKnob::getScrollMode(const QPoint &p, int &scrollMode, int &direction)
00289 {
00290 const int r = d_data->knobRect.width() / 2;
00291
00292 const int dx = d_data->knobRect.x() + r - p.x();
00293 const int dy = d_data->knobRect.y() + r - p.y();
00294
00295 if ( (dx * dx) + (dy * dy) <= (r * r))
00296 {
00297 scrollMode = ScrMouse;
00298 direction = 0;
00299 }
00300 else
00301 {
00302 scrollMode = ScrTimer;
00303 double arc = atan2(double(-dx),double(dy)) * 180.0 / M_PI;
00304 if ( arc < d_data->angle)
00305 direction = -1;
00306 else if (arc > d_data->angle)
00307 direction = 1;
00308 else
00309 direction = 0;
00310 }
00311 }
00312
00313
00319 void QwtKnob::rangeChange()
00320 {
00321 if (autoScale())
00322 rescale(minValue(), maxValue());
00323
00324 layoutKnob();
00325 recalcAngle();
00326 }
00327
00331 void QwtKnob::resizeEvent(QResizeEvent *)
00332 {
00333 layoutKnob( false );
00334 }
00335
00337
00338
00339
00340 void QwtKnob::layoutKnob( bool update_geometry )
00341 {
00342 const QRect r = rect();
00343 const int radius = d_data->knobWidth / 2;
00344
00345 d_data->knobRect.setWidth(2 * radius);
00346 d_data->knobRect.setHeight(2 * radius);
00347 d_data->knobRect.moveCenter(r.center());
00348
00349 scaleDraw()->setRadius(radius + d_data->scaleDist);
00350 scaleDraw()->moveCenter(r.center());
00351
00352 if ( update_geometry )
00353 {
00354 updateGeometry();
00355 update();
00356 }
00357 }
00358
00362 void QwtKnob::paintEvent(QPaintEvent *e)
00363 {
00364 const QRect &ur = e->rect();
00365 if ( ur.isValid() )
00366 {
00367 #if QT_VERSION < 0x040000
00368 QwtPaintBuffer paintBuffer(this, ur);
00369 draw(paintBuffer.painter(), ur);
00370 #else
00371 QPainter painter(this);
00372 if ( paintEngine()->hasFeature(QPaintEngine::Antialiasing) )
00373 painter.setRenderHint(QPainter::Antialiasing);
00374 draw(&painter, ur);
00375 #endif
00376 }
00377 }
00378
00382 void QwtKnob::draw(QPainter *painter, const QRect& ur)
00383 {
00384 if ( !d_data->knobRect.contains( ur ) )
00385 {
00386 #if QT_VERSION < 0x040000
00387 scaleDraw()->draw( painter, colorGroup() );
00388 #else
00389 scaleDraw()->draw( painter, palette() );
00390 #endif
00391 }
00392
00393 drawKnob( painter, d_data->knobRect );
00394
00395 if ( hasFocus() )
00396 QwtPainter::drawFocusRect(painter, this);
00397 }
00398
00405 void QwtKnob::drawMarker(QPainter *p, double arc, const QColor &c)
00406 {
00407 const double rarc = arc * M_PI / 180.0;
00408 const double ca = cos(rarc);
00409 const double sa = - sin(rarc);
00410
00411 int radius = d_data->knobRect.width() / 2 - d_data->borderWidth;
00412 if (radius < 3)
00413 radius = 3;
00414
00415 const int ym = d_data->knobRect.y() + radius + d_data->borderWidth;
00416 const int xm = d_data->knobRect.x() + radius + d_data->borderWidth;
00417
00418 switch (d_data->symbol)
00419 {
00420 case Dot:
00421 {
00422 p->setBrush(c);
00423 p->setPen(Qt::NoPen);
00424
00425 const double rb = double(qwtMax(radius - 4 - d_data->dotWidth / 2, 0));
00426 p->drawEllipse(xm - qRound(sa * rb) - d_data->dotWidth / 2,
00427 ym - qRound(ca * rb) - d_data->dotWidth / 2,
00428 d_data->dotWidth, d_data->dotWidth);
00429 break;
00430 }
00431 case Line:
00432 {
00433 p->setPen(QPen(c, 2));
00434
00435 const double rb = qwtMax(double((radius - 4) / 3.0), 0.0);
00436 const double re = qwtMax(double(radius - 4), 0.0);
00437
00438 p->drawLine ( xm - qRound(sa * rb), ym - qRound(ca * rb),
00439 xm - qRound(sa * re), ym - qRound(ca * re));
00440
00441 break;
00442 }
00443 }
00444 }
00445
00452 void QwtKnob::setKnobWidth(int w)
00453 {
00454 d_data->knobWidth = qwtMax(w,5);
00455 layoutKnob();
00456 }
00457
00459 int QwtKnob::knobWidth() const
00460 {
00461 return d_data->knobWidth;
00462 }
00463
00468 void QwtKnob::setBorderWidth(int bw)
00469 {
00470 d_data->borderWidth = qwtMax(bw, 0);
00471 layoutKnob();
00472 }
00473
00475 int QwtKnob::borderWidth() const
00476 {
00477 return d_data->borderWidth;
00478 }
00479
00484 void QwtKnob::recalcAngle()
00485 {
00486
00487
00488
00489 if (maxValue() == minValue())
00490 {
00491 d_data->angle = 0;
00492 d_data->nTurns = 0;
00493 }
00494 else
00495 {
00496 d_data->angle = (value() - 0.5 * (minValue() + maxValue()))
00497 / (maxValue() - minValue()) * d_data->totalAngle;
00498 d_data->nTurns = floor((d_data->angle + 180.0) / 360.0);
00499 d_data->angle = d_data->angle - d_data->nTurns * 360.0;
00500 }
00501 }
00502
00503
00508 void QwtKnob::scaleChange()
00509 {
00510 layoutKnob();
00511 }
00512
00517 void QwtKnob::fontChange(const QFont &f)
00518 {
00519 QwtAbstractSlider::fontChange( f );
00520 layoutKnob();
00521 }
00522
00526 QSize QwtKnob::sizeHint() const
00527 {
00528 return minimumSizeHint();
00529 }
00530
00536 QSize QwtKnob::minimumSizeHint() const
00537 {
00538
00539 const int sh = scaleDraw()->extent( QPen(), font() );
00540 const int d = 2 * sh + 2 * d_data->scaleDist + d_data->knobWidth;
00541
00542 return QSize( d, d );
00543 }