1
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
3
* Copyright (C) 1997 Josef Wilgen
4
* Copyright (C) 2002 Uwe Rathmann
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the Qwt License, Version 1.0
8
*****************************************************************************/
11
#if QT_VERSION >= 0x040000
12
#include <qpaintengine.h>
17
#include "qwt_round_scale_draw.h"
20
#include "qwt_painter.h"
21
#include "qwt_paint_buffer.h"
23
class QwtKnob::PrivateData
52
QRect knobRect; // bounding rect of the knob without scale
57
\param parent Parent widget
59
QwtKnob::QwtKnob(QWidget* parent):
60
QwtAbstractSlider(Qt::Horizontal, parent)
65
#if QT_VERSION < 0x040000
68
\param parent Parent widget
69
\param name Object name
71
QwtKnob::QwtKnob(QWidget* parent, const char *name):
72
QwtAbstractSlider(Qt::Horizontal, parent)
79
void QwtKnob::initKnob()
81
#if QT_VERSION < 0x040000
82
setWFlags(Qt::WNoAutoErase);
85
d_data = new PrivateData;
87
setScaleDraw(new QwtRoundScaleDraw());
90
setTotalAngle( 270.0 );
92
setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
94
setRange(0.0, 10.0, 1.0);
105
\brief Set the symbol of the knob
108
void QwtKnob::setSymbol(QwtKnob::Symbol s)
110
if ( d_data->symbol != s )
118
\return symbol of the knob
121
QwtKnob::Symbol QwtKnob::symbol() const
123
return d_data->symbol;
127
\brief Set the total angle by which the knob can be turned
128
\param angle Angle in degrees.
130
The default angle is 270 degrees. It is possible to specify
131
an angle of more than 360 degrees so that the knob can be
132
turned several times around its axis.
134
void QwtKnob::setTotalAngle (double angle)
137
d_data->totalAngle = 10.0;
139
d_data->totalAngle = angle;
141
scaleDraw()->setAngleRange( -0.5 * d_data->totalAngle,
142
0.5 * d_data->totalAngle);
146
//! Return the total angle
147
double QwtKnob::totalAngle() const
149
return d_data->totalAngle;
153
Change the scale draw of the knob
155
For changing the labels of the scales, it
156
is necessary to derive from QwtRoundScaleDraw and
157
overload QwtRoundScaleDraw::label().
161
void QwtKnob::setScaleDraw(QwtRoundScaleDraw *scaleDraw)
163
setAbstractScaleDraw(scaleDraw);
164
setTotalAngle(d_data->totalAngle);
168
\return the scale draw of the knob
171
const QwtRoundScaleDraw *QwtKnob::scaleDraw() const
173
return (QwtRoundScaleDraw *)abstractScaleDraw();
177
\return the scale draw of the knob
180
QwtRoundScaleDraw *QwtKnob::scaleDraw()
182
return (QwtRoundScaleDraw *)abstractScaleDraw();
187
\param painter painter
188
\param r Bounding rectangle of the knob (without scale)
190
void QwtKnob::drawKnob(QPainter *painter, const QRect &r)
192
#if QT_VERSION < 0x040000
193
const QBrush buttonBrush = colorGroup().brush(QColorGroup::Button);
194
const QColor buttonTextColor = colorGroup().buttonText();
195
const QColor lightColor = colorGroup().light();
196
const QColor darkColor = colorGroup().dark();
198
const QBrush buttonBrush = palette().brush(QPalette::Button);
199
const QColor buttonTextColor = palette().color(QPalette::ButtonText);
200
const QColor lightColor = palette().color(QPalette::Light);
201
const QColor darkColor = palette().color(QPalette::Dark);
204
const int bw2 = d_data->borderWidth / 2;
206
const int radius = (qwtMin(r.width(), r.height()) - bw2) / 2;
209
r.center().x() - radius, r.center().y() - radius,
210
2 * radius, 2 * radius);
215
painter->setBrush(buttonBrush);
216
painter->drawEllipse(aRect);
219
// draw button shades
222
pn.setWidth(d_data->borderWidth);
224
pn.setColor(lightColor);
226
painter->drawArc(aRect, 45*16, 180*16);
228
pn.setColor(darkColor);
230
painter->drawArc(aRect, 225*16, 180*16);
236
drawMarker(painter, d_data->angle, buttonTextColor);
240
\brief Notify change of value
242
Sets the knob's value to the nearest multiple
245
void QwtKnob::valueChange()
249
QwtAbstractSlider::valueChange();
253
\brief Determine the value corresponding to a specified position
255
Called by QwtAbstractSlider
258
double QwtKnob::getValue(const QPoint &p)
260
const double dx = double((rect().x() + rect().width() / 2) - p.x() );
261
const double dy = double((rect().y() + rect().height() / 2) - p.y() );
263
const double arc = atan2(-dx,dy) * 180.0 / M_PI;
265
double newValue = 0.5 * (minValue() + maxValue())
266
+ (arc + d_data->nTurns * 360.0) * (maxValue() - minValue())
267
/ d_data->totalAngle;
269
const double oneTurn = fabs(maxValue() - minValue()) * 360.0 / d_data->totalAngle;
270
const double eqValue = value() + mouseOffset();
272
if (fabs(newValue - eqValue) > 0.5 * oneTurn)
274
if (newValue < eqValue)
284
\brief Set the scrolling mode and direction
286
Called by QwtAbstractSlider
287
\param p Point in question
289
void QwtKnob::getScrollMode(const QPoint &p, int &scrollMode, int &direction)
291
const int r = d_data->knobRect.width() / 2;
293
const int dx = d_data->knobRect.x() + r - p.x();
294
const int dy = d_data->knobRect.y() + r - p.y();
296
if ( (dx * dx) + (dy * dy) <= (r * r)) // point is inside the knob
298
scrollMode = ScrMouse;
301
else // point lies outside
303
scrollMode = ScrTimer;
304
double arc = atan2(double(-dx),double(dy)) * 180.0 / M_PI;
305
if ( arc < d_data->angle)
307
else if (arc > d_data->angle)
316
\brief Notify a change of the range
318
Called by QwtAbstractSlider
320
void QwtKnob::rangeChange()
323
rescale(minValue(), maxValue());
330
\brief Qt Resize Event
332
void QwtKnob::resizeEvent(QResizeEvent *)
337
//! Recalculate the knob's geometry and layout based on
338
// the current rect and fonts.
339
// \param update_geometry notify the layout system and call update
340
// to redraw the scale
341
void QwtKnob::layoutKnob( bool update_geometry )
343
const QRect r = rect();
344
const int radius = d_data->knobWidth / 2;
346
d_data->knobRect.setWidth(2 * radius);
347
d_data->knobRect.setHeight(2 * radius);
348
d_data->knobRect.moveCenter(r.center());
350
scaleDraw()->setRadius(radius + d_data->scaleDist);
351
scaleDraw()->moveCenter(r.center());
353
if ( update_geometry )
361
\brief Repaint the knob
363
void QwtKnob::paintEvent(QPaintEvent *e)
365
const QRect &ur = e->rect();
368
#if QT_VERSION < 0x040000
369
QwtPaintBuffer paintBuffer(this, ur);
370
draw(paintBuffer.painter(), ur);
372
QPainter painter(this);
373
if ( paintEngine()->hasFeature(QPaintEngine::Antialiasing) )
374
painter.setRenderHint(QPainter::Antialiasing);
381
\brief Repaint the knob
383
void QwtKnob::draw(QPainter *painter, const QRect& ur)
385
if ( !d_data->knobRect.contains( ur ) ) // event from valueChange()
387
#if QT_VERSION < 0x040000
388
scaleDraw()->draw( painter, colorGroup() );
390
scaleDraw()->draw( painter, palette() );
394
drawKnob( painter, d_data->knobRect );
397
QwtPainter::drawFocusRect(painter, this);
401
\brief Draw the marker at the knob's front
403
\param arc Angle of the marker
404
\param c Marker color
406
void QwtKnob::drawMarker(QPainter *p, double arc, const QColor &c)
408
const double rarc = arc * M_PI / 180.0;
409
const double ca = cos(rarc);
410
const double sa = - sin(rarc);
412
int radius = d_data->knobRect.width() / 2 - d_data->borderWidth;
416
const int ym = d_data->knobRect.y() + radius + d_data->borderWidth;
417
const int xm = d_data->knobRect.x() + radius + d_data->borderWidth;
419
switch (d_data->symbol)
424
p->setPen(Qt::NoPen);
426
const double rb = double(qwtMax(radius - 4 - d_data->dotWidth / 2, 0));
427
p->drawEllipse(xm - qRound(sa * rb) - d_data->dotWidth / 2,
428
ym - qRound(ca * rb) - d_data->dotWidth / 2,
429
d_data->dotWidth, d_data->dotWidth);
434
p->setPen(QPen(c, 2));
436
const double rb = qwtMax(double((radius - 4) / 3.0), 0.0);
437
const double re = qwtMax(double(radius - 4), 0.0);
439
p->drawLine ( xm - qRound(sa * rb), ym - qRound(ca * rb),
440
xm - qRound(sa * re), ym - qRound(ca * re));
448
\brief Change the knob's width.
450
The specified width must be >= 5, or it will be clipped.
453
void QwtKnob::setKnobWidth(int w)
455
d_data->knobWidth = qwtMax(w,5);
459
//! Return the width of the knob
460
int QwtKnob::knobWidth() const
462
return d_data->knobWidth;
466
\brief Set the knob's border width
467
\param bw new border width
469
void QwtKnob::setBorderWidth(int bw)
471
d_data->borderWidth = qwtMax(bw, 0);
475
//! Return the border width
476
int QwtKnob::borderWidth() const
478
return d_data->borderWidth;
482
\brief Recalculate the marker angle corresponding to the
485
void QwtKnob::recalcAngle()
488
// calculate the angle corresponding to the value
490
if (maxValue() == minValue())
497
d_data->angle = (value() - 0.5 * (minValue() + maxValue()))
498
/ (maxValue() - minValue()) * d_data->totalAngle;
499
d_data->nTurns = floor((d_data->angle + 180.0) / 360.0);
500
d_data->angle = d_data->angle - d_data->nTurns * 360.0;
506
Recalculates the layout
509
void QwtKnob::scaleChange()
515
Recalculates the layout
518
void QwtKnob::fontChange(const QFont &f)
520
QwtAbstractSlider::fontChange( f );
525
\return minimumSizeHint()
527
QSize QwtKnob::sizeHint() const
529
return minimumSizeHint();
533
\brief Return a minimum size hint
534
\warning The return value of QwtKnob::minimumSizeHint() depends on the
537
QSize QwtKnob::minimumSizeHint() const
539
// Add the scale radial thickness to the knobWidth
540
const int sh = scaleDraw()->extent( QPen(), font() );
541
const int d = 2 * sh + 2 * d_data->scaleDist + d_data->knobWidth;
543
return QSize( d, d );