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_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 oldAngle = 0.0;
00030 nTurns = 0.0;
00031 borderWidth = 2;
00032 borderDist = 4;
00033 totalAngle = 270.0;
00034 scaleDist = 4;
00035 hasScale = 0;
00036 symbol = Line;
00037 maxScaleTicks = 11;
00038 knobWidth = 50;
00039 dotWidth = 8;
00040 }
00041
00042 int borderWidth;
00043 int borderDist;
00044 int hasScale;
00045 int scaleDist;
00046 int maxScaleTicks;
00047 int knobWidth;
00048 int dotWidth;
00049
00050 Symbol symbol;
00051 double angle;
00052 double oldAngle;
00053 double totalAngle;
00054 double nTurns;
00055
00056 QRect kRect;
00057 };
00058
00064 QwtKnob::QwtKnob(QWidget* parent):
00065 QwtAbstractSlider(Qt::Horizontal, parent)
00066 {
00067 #if QT_VERSION < 0x040000
00068 setWFlags(Qt::WNoAutoErase);
00069 #endif
00070
00071 d_data = new PrivateData;
00072
00073 scaleDraw()->setGeometry(
00074 0, 0, d_data->knobWidth + 2 * d_data->scaleDist, QwtScaleDraw::Round );
00075 setUpdateTime(50);
00076 setTotalAngle( 270.0 );
00077 recalcAngle();
00078 setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
00079
00080 setRange(0.0, 10.0, 1.0);
00081 setValue(0.0);
00082 }
00083
00085 QwtKnob::~QwtKnob()
00086 {
00087 delete d_data;
00088 }
00089
00094 void QwtKnob::setSymbol(QwtKnob::Symbol s)
00095 {
00096 if ( d_data->symbol != s )
00097 {
00098 d_data->symbol = s;
00099 update();
00100 }
00101 }
00102
00107 QwtKnob::Symbol QwtKnob::symbol() const
00108 {
00109 return d_data->symbol;
00110 }
00111
00120 void QwtKnob::setTotalAngle (double angle)
00121 {
00122 if (angle < 10.0)
00123 d_data->totalAngle = 10.0;
00124 else
00125 d_data->totalAngle = angle;
00126
00127 scaleDraw()->setAngleRange( -0.5 * d_data->totalAngle,
00128 0.5 * d_data->totalAngle);
00129 layoutKnob();
00130 }
00131
00133 double QwtKnob::totalAngle() const
00134 {
00135 return d_data->totalAngle;
00136 }
00137
00138
00139
00145 void QwtKnob::drawKnob(QPainter *p, const QRect &r)
00146 {
00147 #if QT_VERSION < 0x040000
00148 const QBrush buttonBrush = colorGroup().brush(QColorGroup::Button);
00149 const QColor buttonTextColor = colorGroup().buttonText();
00150 const QColor lightColor = colorGroup().light();
00151 const QColor darkColor = colorGroup().dark();
00152 #else
00153 const QBrush buttonBrush = palette().brush(QPalette::Button);
00154 const QColor buttonTextColor = palette().color(QPalette::ButtonText);
00155 const QColor lightColor = palette().color(QPalette::Light);
00156 const QColor darkColor = palette().color(QPalette::Dark);
00157 #endif
00158 const int bw2 = d_data->borderWidth / 2;
00159
00160 QRect aRect(r.x() + bw2, r.y() + bw2,
00161 r.width() - 2 * bw2, r.height() - 2 * bw2);
00162
00163
00164
00165
00166 p->setBrush(buttonBrush);
00167 p->drawEllipse(aRect);
00168
00169
00170
00171
00172 QPen pn;
00173 pn.setWidth(d_data->borderWidth);
00174
00175 pn.setColor(lightColor);
00176 p->setPen(pn);
00177 p->drawArc(aRect, 45*16,180*16);
00178
00179 pn.setColor(darkColor);
00180 p->setPen(pn);
00181 p->drawArc(aRect, 225*16,180*16);
00182
00183
00184
00185
00186 if ( isValid() )
00187 drawMarker(p, d_data->angle, buttonTextColor);
00188 }
00189
00196 void QwtKnob::valueChange()
00197 {
00198 recalcAngle();
00199 update();
00200 QwtAbstractSlider::valueChange();
00201 }
00202
00209 double QwtKnob::getValue(const QPoint &p)
00210 {
00211 const double dx = double((rect().x() + rect().width() / 2) - p.x() );
00212 const double dy = double((rect().y() + rect().height() / 2) - p.y() );
00213
00214 const double arc = atan2(-dx,dy) * 180.0 / M_PI;
00215
00216 double newValue = 0.5 * (minValue() + maxValue())
00217 + (arc + d_data->nTurns * 360.0) * (maxValue() - minValue())
00218 / d_data->totalAngle;
00219
00220 const double oneTurn = fabs(maxValue() - minValue()) * 360.0 / d_data->totalAngle;
00221 const double eqValue = value() + mouseOffset();
00222
00223 if (fabs(newValue - eqValue) > 0.5 * oneTurn)
00224 {
00225 if (newValue < eqValue)
00226 newValue += oneTurn;
00227 else
00228 newValue -= oneTurn;
00229 }
00230
00231 return newValue;
00232 }
00233
00240 void QwtKnob::getScrollMode(const QPoint &p, int &scrollMode, int &direction)
00241 {
00242 const int r = d_data->kRect.width() / 2;
00243
00244 const int dx = d_data->kRect.x() + r - p.x();
00245 const int dy = d_data->kRect.y() + r - p.y();
00246
00247 if ( (dx * dx) + (dy * dy) <= (r * r))
00248 {
00249 scrollMode = ScrMouse;
00250 direction = 0;
00251 }
00252 else
00253 {
00254 scrollMode = ScrTimer;
00255 double arc = atan2(double(-dx),double(dy)) * 180.0 / M_PI;
00256 if ( arc < d_data->angle)
00257 direction = -1;
00258 else if (arc > d_data->angle)
00259 direction = 1;
00260 else
00261 direction = 0;
00262 }
00263 }
00264
00265
00271 void QwtKnob::rangeChange()
00272 {
00273 if (autoScale())
00274 rescale(minValue(), maxValue());
00275
00276 layoutKnob();
00277 recalcAngle();
00278 }
00279
00283 void QwtKnob::resizeEvent(QResizeEvent *)
00284 {
00285 layoutKnob( false );
00286 }
00287
00289
00290
00291
00292 void QwtKnob::layoutKnob( bool update_geometry )
00293 {
00294 const QRect &r = rect();
00295
00296 const int width = qwtMin(qwtMin(r.height(), r.width()), d_data->knobWidth);
00297 const int width_2 = width / 2;
00298
00299 d_data->kRect.setRect(r.x() + r.width() / 2 - width_2,
00300 r.y() + r.height() / 2 - width_2,
00301 width, width);
00302
00303 scaleDraw()->setGeometry(d_data->kRect.x() - d_data->scaleDist,
00304 d_data->kRect.y() - d_data->scaleDist,
00305 width + 2 * d_data->scaleDist, QwtScaleDraw::Round );
00306
00307 if ( update_geometry )
00308 {
00309 updateGeometry();
00310 update();
00311 }
00312 }
00313
00317 void QwtKnob::paintEvent(QPaintEvent *e)
00318 {
00319 const QRect &ur = e->rect();
00320 if ( ur.isValid() )
00321 {
00322 #if QT_VERSION < 0x040000
00323 QwtPaintBuffer paintBuffer(this, ur);
00324 draw(paintBuffer.painter(), ur);
00325 #else
00326 QPainter painter(this);
00327 if ( paintEngine()->hasFeature(QPaintEngine::Antialiasing) )
00328 painter.setRenderHint(QPainter::Antialiasing);
00329 draw(&painter, ur);
00330 #endif
00331 }
00332 }
00333
00337 void QwtKnob::draw(QPainter *painter, const QRect& ur)
00338 {
00339 if ( !d_data->kRect.contains( ur ) )
00340 {
00341 #if QT_VERSION < 0x040000
00342 scaleDraw()->draw( painter, colorGroup() );
00343 #else
00344 scaleDraw()->draw( painter, palette() );
00345 #endif
00346 }
00347
00348 drawKnob( painter, d_data->kRect );
00349
00350 if ( hasFocus() )
00351 QwtPainter::drawFocusRect(painter, this);
00352 }
00353
00360 void QwtKnob::drawMarker(QPainter *p, double arc, const QColor &c)
00361 {
00362 const double rarc = arc * M_PI / 180.0;
00363 const double ca = cos(rarc);
00364 const double sa = - sin(rarc);
00365
00366 int radius = d_data->kRect.width() / 2 - d_data->borderWidth;
00367 if (radius < 3)
00368 radius = 3;
00369
00370 const int ym = d_data->kRect.y() + radius + d_data->borderWidth;
00371 const int xm = d_data->kRect.x() + radius + d_data->borderWidth;
00372
00373 switch (d_data->symbol)
00374 {
00375 case Dot:
00376 {
00377 p->setBrush(c);
00378 p->setPen(Qt::NoPen);
00379
00380 const double rb = double(qwtMax(radius - 4 - d_data->dotWidth / 2, 0));
00381 p->drawEllipse(xm - qRound(sa * rb) - d_data->dotWidth / 2,
00382 ym - qRound(ca * rb) - d_data->dotWidth / 2,
00383 d_data->dotWidth, d_data->dotWidth);
00384 break;
00385 }
00386 case Line:
00387 {
00388 p->setPen(QPen(c, 2));
00389
00390 const double rb = qwtMax(double((radius - 4) / 3.0), 0.0);
00391 const double re = qwtMax(double(radius - 4), 0.0);
00392
00393 p->drawLine ( xm - qRound(sa * rb), ym - qRound(ca * rb),
00394 xm - qRound(sa * re), ym - qRound(ca * re));
00395
00396 break;
00397 }
00398 }
00399 }
00400
00407 void QwtKnob::setKnobWidth(int w)
00408 {
00409 d_data->knobWidth = qwtMax(w,5);
00410 layoutKnob();
00411 }
00412
00414 int QwtKnob::knobWidth() const
00415 {
00416 return d_data->knobWidth;
00417 }
00418
00423 void QwtKnob::setBorderWidth(int bw)
00424 {
00425 d_data->borderWidth = qwtMax(bw, 0);
00426 layoutKnob();
00427 }
00428
00430 int QwtKnob::borderWidth() const
00431 {
00432 return d_data->borderWidth;
00433 }
00434
00439 void QwtKnob::recalcAngle()
00440 {
00441 d_data->oldAngle = d_data->angle;
00442
00443
00444
00445
00446 if (maxValue() == minValue())
00447 {
00448 d_data->angle = 0;
00449 d_data->nTurns = 0;
00450 }
00451 else
00452 {
00453 d_data->angle = (value() - 0.5 * (minValue() + maxValue()))
00454 / (maxValue() - minValue()) * d_data->totalAngle;
00455 d_data->nTurns = floor((d_data->angle + 180.0) / 360.0);
00456 d_data->angle = d_data->angle - d_data->nTurns * 360.0;
00457 }
00458 }
00459
00460
00465 void QwtKnob::scaleChange()
00466 {
00467 layoutKnob();
00468 }
00469
00474 void QwtKnob::fontChange(const QFont &f)
00475 {
00476 QwtAbstractSlider::fontChange( f );
00477 layoutKnob();
00478 }
00479
00483 QSize QwtKnob::sizeHint() const
00484 {
00485 return minimumSizeHint();
00486 }
00487
00493 QSize QwtKnob::minimumSizeHint() const
00494 {
00495
00496 const int sh = scaleDraw()->minHeight( QPen(), font() );
00497 const int d = 2 * sh + 2 * d_data->scaleDist + d_data->knobWidth;
00498
00499 return QSize( d, d );
00500 }