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
*****************************************************************************/
14
#include "qwt_round_scale_draw.h"
17
#include "qwt_painter.h"
18
#include "qwt_paint_buffer.h"
20
class QwtKnob::PrivateData
49
QRect knobRect; // bounding rect of the knob without scale
54
\param parent Parent widget
56
QwtKnob::QwtKnob(QWidget* parent):
57
QwtAbstractSlider(Qt::Horizontal, parent)
62
#if QT_VERSION < 0x040000
65
\param parent Parent widget
66
\param name Object name
68
QwtKnob::QwtKnob(QWidget* parent, const char *name):
69
QwtAbstractSlider(Qt::Horizontal, parent)
76
void QwtKnob::initKnob()
78
#if QT_VERSION < 0x040000
79
setWFlags(Qt::WNoAutoErase);
82
d_data = new PrivateData;
84
setScaleDraw(new QwtRoundScaleDraw());
87
setTotalAngle( 270.0 );
89
setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
91
setRange(0.0, 10.0, 1.0);
102
\brief Set the symbol of the knob
105
void QwtKnob::setSymbol(QwtKnob::Symbol s)
107
if ( d_data->symbol != s )
115
\return symbol of the knob
118
QwtKnob::Symbol QwtKnob::symbol() const
120
return d_data->symbol;
124
\brief Set the total angle by which the knob can be turned
125
\param angle Angle in degrees.
127
The default angle is 270 degrees. It is possible to specify
128
an angle of more than 360 degrees so that the knob can be
129
turned several times around its axis.
131
void QwtKnob::setTotalAngle (double angle)
134
d_data->totalAngle = 10.0;
136
d_data->totalAngle = angle;
138
scaleDraw()->setAngleRange( -0.5 * d_data->totalAngle,
139
0.5 * d_data->totalAngle);
143
//! Return the total angle
144
double QwtKnob::totalAngle() const
146
return d_data->totalAngle;
150
Change the scale draw of the knob
152
For changing the labels of the scales, it
153
is necessary to derive from QwtRoundScaleDraw and
154
overload QwtRoundScaleDraw::label().
158
void QwtKnob::setScaleDraw(QwtRoundScaleDraw *scaleDraw)
160
setAbstractScaleDraw(scaleDraw);
161
setTotalAngle(d_data->totalAngle);
165
\return the scale draw of the knob
168
const QwtRoundScaleDraw *QwtKnob::scaleDraw() const
170
return (QwtRoundScaleDraw *)abstractScaleDraw();
174
\return the scale draw of the knob
177
QwtRoundScaleDraw *QwtKnob::scaleDraw()
179
return (QwtRoundScaleDraw *)abstractScaleDraw();
184
\param painter painter
185
\param r Bounding rectangle of the knob (without scale)
187
void QwtKnob::drawKnob(QPainter *painter, const QRect &r)
189
#if QT_VERSION < 0x040000
190
const QBrush buttonBrush = colorGroup().brush(QColorGroup::Button);
191
const QColor buttonTextColor = colorGroup().buttonText();
192
const QColor lightColor = colorGroup().light();
193
const QColor darkColor = colorGroup().dark();
195
const QBrush buttonBrush = palette().brush(QPalette::Button);
196
const QColor buttonTextColor = palette().color(QPalette::ButtonText);
197
const QColor lightColor = palette().color(QPalette::Light);
198
const QColor darkColor = palette().color(QPalette::Dark);
201
const int bw2 = d_data->borderWidth / 2;
203
const int radius = (qwtMin(r.width(), r.height()) - bw2) / 2;
206
r.center().x() - radius, r.center().y() - radius,
207
2 * radius, 2 * radius);
212
painter->setBrush(buttonBrush);
213
painter->drawEllipse(aRect);
216
// draw button shades
219
pn.setWidth(d_data->borderWidth);
221
pn.setColor(lightColor);
223
painter->drawArc(aRect, 45*16, 180*16);
225
pn.setColor(darkColor);
227
painter->drawArc(aRect, 225*16, 180*16);
233
drawMarker(painter, d_data->angle, buttonTextColor);
237
\brief Notify change of value
239
Sets the knob's value to the nearest multiple
242
void QwtKnob::valueChange()
246
QwtAbstractSlider::valueChange();
250
\brief Determine the value corresponding to a specified position
252
Called by QwtAbstractSlider
255
double QwtKnob::getValue(const QPoint &p)
257
const double dx = double((rect().x() + rect().width() / 2) - p.x() );
258
const double dy = double((rect().y() + rect().height() / 2) - p.y() );
260
const double arc = atan2(-dx,dy) * 180.0 / M_PI;
262
double newValue = 0.5 * (minValue() + maxValue())
263
+ (arc + d_data->nTurns * 360.0) * (maxValue() - minValue())
264
/ d_data->totalAngle;
266
const double oneTurn = fabs(maxValue() - minValue()) * 360.0 / d_data->totalAngle;
267
const double eqValue = value() + mouseOffset();
269
if (fabs(newValue - eqValue) > 0.5 * oneTurn)
271
if (newValue < eqValue)
281
\brief Set the scrolling mode and direction
283
Called by QwtAbstractSlider
284
\param p Point in question
286
void QwtKnob::getScrollMode(const QPoint &p, int &scrollMode, int &direction)
288
const int r = d_data->knobRect.width() / 2;
290
const int dx = d_data->knobRect.x() + r - p.x();
291
const int dy = d_data->knobRect.y() + r - p.y();
293
if ( (dx * dx) + (dy * dy) <= (r * r)) // point is inside the knob
295
scrollMode = ScrMouse;
298
else // point lies outside
300
scrollMode = ScrTimer;
301
double arc = atan2(double(-dx),double(dy)) * 180.0 / M_PI;
302
if ( arc < d_data->angle)
304
else if (arc > d_data->angle)
313
\brief Notify a change of the range
315
Called by QwtAbstractSlider
317
void QwtKnob::rangeChange()
320
rescale(minValue(), maxValue());
327
\brief Qt Resize Event
329
void QwtKnob::resizeEvent(QResizeEvent *)
334
//! Recalculate the knob's geometry and layout based on
335
// the current rect and fonts.
336
// \param update_geometry notify the layout system and call update
337
// to redraw the scale
338
void QwtKnob::layoutKnob( bool update_geometry )
340
const QRect r = rect();
341
const int radius = d_data->knobWidth / 2;
343
d_data->knobRect.setWidth(2 * radius);
344
d_data->knobRect.setHeight(2 * radius);
345
d_data->knobRect.moveCenter(r.center());
347
scaleDraw()->setRadius(radius + d_data->scaleDist);
348
scaleDraw()->moveCenter(r.center());
350
if ( update_geometry )
358
\brief Repaint the knob
360
void QwtKnob::paintEvent(QPaintEvent *e)
362
const QRect &ur = e->rect();
365
#if QT_VERSION < 0x040000
366
QwtPaintBuffer paintBuffer(this, ur);
367
draw(paintBuffer.painter(), ur);
369
QPainter painter(this);
370
painter.setRenderHint(QPainter::Antialiasing);
377
\brief Repaint the knob
379
void QwtKnob::draw(QPainter *painter, const QRect& ur)
381
if ( !d_data->knobRect.contains( ur ) ) // event from valueChange()
383
#if QT_VERSION < 0x040000
384
scaleDraw()->draw( painter, colorGroup() );
386
scaleDraw()->draw( painter, palette() );
390
drawKnob( painter, d_data->knobRect );
393
QwtPainter::drawFocusRect(painter, this);
397
\brief Draw the marker at the knob's front
399
\param arc Angle of the marker
400
\param c Marker color
402
void QwtKnob::drawMarker(QPainter *p, double arc, const QColor &c)
404
const double rarc = arc * M_PI / 180.0;
405
const double ca = cos(rarc);
406
const double sa = - sin(rarc);
408
int radius = d_data->knobRect.width() / 2 - d_data->borderWidth;
412
const int ym = d_data->knobRect.y() + radius + d_data->borderWidth;
413
const int xm = d_data->knobRect.x() + radius + d_data->borderWidth;
415
switch (d_data->symbol)
420
p->setPen(Qt::NoPen);
422
const double rb = double(qwtMax(radius - 4 - d_data->dotWidth / 2, 0));
423
p->drawEllipse(xm - qRound(sa * rb) - d_data->dotWidth / 2,
424
ym - qRound(ca * rb) - d_data->dotWidth / 2,
425
d_data->dotWidth, d_data->dotWidth);
430
p->setPen(QPen(c, 2));
432
const double rb = qwtMax(double((radius - 4) / 3.0), 0.0);
433
const double re = qwtMax(double(radius - 4), 0.0);
435
p->drawLine ( xm - qRound(sa * rb), ym - qRound(ca * rb),
436
xm - qRound(sa * re), ym - qRound(ca * re));
444
\brief Change the knob's width.
446
The specified width must be >= 5, or it will be clipped.
449
void QwtKnob::setKnobWidth(int w)
451
d_data->knobWidth = qwtMax(w,5);
455
//! Return the width of the knob
456
int QwtKnob::knobWidth() const
458
return d_data->knobWidth;
462
\brief Set the knob's border width
463
\param bw new border width
465
void QwtKnob::setBorderWidth(int bw)
467
d_data->borderWidth = qwtMax(bw, 0);
471
//! Return the border width
472
int QwtKnob::borderWidth() const
474
return d_data->borderWidth;
478
\brief Recalculate the marker angle corresponding to the
481
void QwtKnob::recalcAngle()
484
// calculate the angle corresponding to the value
486
if (maxValue() == minValue())
493
d_data->angle = (value() - 0.5 * (minValue() + maxValue()))
494
/ (maxValue() - minValue()) * d_data->totalAngle;
495
d_data->nTurns = floor((d_data->angle + 180.0) / 360.0);
496
d_data->angle = d_data->angle - d_data->nTurns * 360.0;
502
Recalculates the layout
505
void QwtKnob::scaleChange()
511
Recalculates the layout
514
void QwtKnob::fontChange(const QFont &f)
516
QwtAbstractSlider::fontChange( f );
521
\return minimumSizeHint()
523
QSize QwtKnob::sizeHint() const
525
return minimumSizeHint();
529
\brief Return a minimum size hint
530
\warning The return value of QwtKnob::minimumSizeHint() depends on the
533
QSize QwtKnob::minimumSizeHint() const
535
// Add the scale radial thickness to the knobWidth
536
const int sh = scaleDraw()->extent( QPen(), font() );
537
const int d = 2 * sh + 2 * d_data->scaleDist + d_data->knobWidth;
539
return QSize( d, d );