You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
526 lines
0 B
526 lines
0 B
15 years ago
|
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||
|
* Qwt Widget Library
|
||
|
* Copyright (C) 1997 Josef Wilgen
|
||
|
* Copyright (C) 2002 Uwe Rathmann
|
||
|
*
|
||
|
* This library is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the Qwt License, Version 1.0
|
||
|
*****************************************************************************/
|
||
|
|
||
|
#include <qpainter.h>
|
||
|
#include <qpalette.h>
|
||
|
#include <qstyle.h>
|
||
|
#include <qevent.h>
|
||
|
#include "qwt_round_scale_draw.h"
|
||
|
#include "qwt_knob.h"
|
||
|
#include "qwt_math.h"
|
||
|
#include "qwt_painter.h"
|
||
|
#include "qwt_paint_buffer.h"
|
||
|
|
||
|
class QwtKnob::PrivateData
|
||
|
{
|
||
|
public:
|
||
14 years ago
|
PrivateData() {
|
||
15 years ago
|
angle = 0.0;
|
||
|
nTurns = 0.0;
|
||
|
borderWidth = 2;
|
||
|
borderDist = 4;
|
||
|
totalAngle = 270.0;
|
||
|
scaleDist = 4;
|
||
|
symbol = Line;
|
||
|
maxScaleTicks = 11;
|
||
|
knobWidth = 50;
|
||
|
dotWidth = 8;
|
||
|
}
|
||
|
|
||
|
int borderWidth;
|
||
|
int borderDist;
|
||
|
int scaleDist;
|
||
|
int maxScaleTicks;
|
||
|
int knobWidth;
|
||
|
int dotWidth;
|
||
|
|
||
|
Symbol symbol;
|
||
|
double angle;
|
||
|
double totalAngle;
|
||
|
double nTurns;
|
||
|
|
||
|
QRect knobRect; // bounding rect of the knob without scale
|
||
|
};
|
||
|
|
||
|
/*!
|
||
|
Constructor
|
||
|
\param parent Parent widget
|
||
|
*/
|
||
14 years ago
|
QwtKnob::QwtKnob(QWidget* parent):
|
||
15 years ago
|
QwtAbstractSlider(Qt::Horizontal, parent)
|
||
|
{
|
||
|
initKnob();
|
||
|
}
|
||
|
|
||
|
#if QT_VERSION < 0x040000
|
||
|
/*!
|
||
|
Constructor
|
||
|
\param parent Parent widget
|
||
|
\param name Object name
|
||
|
*/
|
||
14 years ago
|
QwtKnob::QwtKnob(QWidget* parent, const char *name):
|
||
15 years ago
|
QwtAbstractSlider(Qt::Horizontal, parent)
|
||
|
{
|
||
|
setName(name);
|
||
|
initKnob();
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
void QwtKnob::initKnob()
|
||
|
{
|
||
|
#if QT_VERSION < 0x040000
|
||
|
setWFlags(Qt::WNoAutoErase);
|
||
|
#endif
|
||
|
|
||
|
d_data = new PrivateData;
|
||
|
|
||
|
setScaleDraw(new QwtRoundScaleDraw());
|
||
|
|
||
|
setUpdateTime(50);
|
||
|
setTotalAngle( 270.0 );
|
||
|
recalcAngle();
|
||
|
setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
|
||
|
|
||
|
setRange(0.0, 10.0, 1.0);
|
||
|
setValue(0.0);
|
||
|
}
|
||
|
|
||
|
//! Destructor
|
||
|
QwtKnob::~QwtKnob()
|
||
|
{
|
||
|
delete d_data;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Set the symbol of the knob
|
||
|
\sa symbol()
|
||
|
*/
|
||
|
void QwtKnob::setSymbol(QwtKnob::Symbol s)
|
||
|
{
|
||
14 years ago
|
if ( d_data->symbol != s ) {
|
||
15 years ago
|
d_data->symbol = s;
|
||
|
update();
|
||
|
}
|
||
|
}
|
||
|
|
||
14 years ago
|
/*!
|
||
15 years ago
|
\return symbol of the knob
|
||
|
\sa setSymbol()
|
||
|
*/
|
||
|
QwtKnob::Symbol QwtKnob::symbol() const
|
||
|
{
|
||
|
return d_data->symbol;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Set the total angle by which the knob can be turned
|
||
|
\param angle Angle in degrees.
|
||
|
|
||
|
The default angle is 270 degrees. It is possible to specify
|
||
|
an angle of more than 360 degrees so that the knob can be
|
||
|
turned several times around its axis.
|
||
|
*/
|
||
|
void QwtKnob::setTotalAngle (double angle)
|
||
|
{
|
||
|
if (angle < 10.0)
|
||
14 years ago
|
d_data->totalAngle = 10.0;
|
||
15 years ago
|
else
|
||
14 years ago
|
d_data->totalAngle = angle;
|
||
15 years ago
|
|
||
14 years ago
|
scaleDraw()->setAngleRange( -0.5 * d_data->totalAngle,
|
||
|
0.5 * d_data->totalAngle);
|
||
15 years ago
|
layoutKnob();
|
||
|
}
|
||
|
|
||
|
//! Return the total angle
|
||
14 years ago
|
double QwtKnob::totalAngle() const
|
||
15 years ago
|
{
|
||
|
return d_data->totalAngle;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Change the scale draw of the knob
|
||
|
|
||
|
For changing the labels of the scales, it
|
||
|
is necessary to derive from QwtRoundScaleDraw and
|
||
14 years ago
|
overload QwtRoundScaleDraw::label().
|
||
15 years ago
|
|
||
|
\sa scaleDraw()
|
||
|
*/
|
||
|
void QwtKnob::setScaleDraw(QwtRoundScaleDraw *scaleDraw)
|
||
|
{
|
||
|
setAbstractScaleDraw(scaleDraw);
|
||
|
setTotalAngle(d_data->totalAngle);
|
||
|
}
|
||
|
|
||
14 years ago
|
/*!
|
||
15 years ago
|
\return the scale draw of the knob
|
||
|
\sa setScaleDraw()
|
||
|
*/
|
||
|
const QwtRoundScaleDraw *QwtKnob::scaleDraw() const
|
||
|
{
|
||
|
return (QwtRoundScaleDraw *)abstractScaleDraw();
|
||
|
}
|
||
|
|
||
14 years ago
|
/*!
|
||
15 years ago
|
\return the scale draw of the knob
|
||
|
\sa setScaleDraw()
|
||
|
*/
|
||
|
QwtRoundScaleDraw *QwtKnob::scaleDraw()
|
||
|
{
|
||
|
return (QwtRoundScaleDraw *)abstractScaleDraw();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Draw the knob
|
||
|
\param painter painter
|
||
|
\param r Bounding rectangle of the knob (without scale)
|
||
|
*/
|
||
|
void QwtKnob::drawKnob(QPainter *painter, const QRect &r)
|
||
|
{
|
||
|
#if QT_VERSION < 0x040000
|
||
|
const QBrush buttonBrush = colorGroup().brush(QColorGroup::Button);
|
||
|
const QColor buttonTextColor = colorGroup().buttonText();
|
||
|
const QColor lightColor = colorGroup().light();
|
||
|
const QColor darkColor = colorGroup().dark();
|
||
|
#else
|
||
|
const QBrush buttonBrush = palette().brush(QPalette::Button);
|
||
|
const QColor buttonTextColor = palette().color(QPalette::ButtonText);
|
||
|
const QColor lightColor = palette().color(QPalette::Light);
|
||
|
const QColor darkColor = palette().color(QPalette::Dark);
|
||
|
#endif
|
||
|
|
||
|
const int bw2 = d_data->borderWidth / 2;
|
||
|
|
||
|
const int radius = (qwtMin(r.width(), r.height()) - bw2) / 2;
|
||
|
|
||
14 years ago
|
const QRect aRect(
|
||
15 years ago
|
r.center().x() - radius, r.center().y() - radius,
|
||
|
2 * radius, 2 * radius);
|
||
|
|
||
|
//
|
||
|
// draw button face
|
||
|
//
|
||
|
painter->setBrush(buttonBrush);
|
||
|
painter->drawEllipse(aRect);
|
||
|
|
||
|
//
|
||
|
// draw button shades
|
||
|
//
|
||
|
QPen pn;
|
||
|
pn.setWidth(d_data->borderWidth);
|
||
|
|
||
|
pn.setColor(lightColor);
|
||
|
painter->setPen(pn);
|
||
|
painter->drawArc(aRect, 45*16, 180*16);
|
||
|
|
||
|
pn.setColor(darkColor);
|
||
|
painter->setPen(pn);
|
||
|
painter->drawArc(aRect, 225*16, 180*16);
|
||
|
|
||
|
//
|
||
|
// draw marker
|
||
|
//
|
||
|
if ( isValid() )
|
||
|
drawMarker(painter, d_data->angle, buttonTextColor);
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Notify change of value
|
||
|
|
||
|
Sets the knob's value to the nearest multiple
|
||
|
of the step size.
|
||
|
*/
|
||
|
void QwtKnob::valueChange()
|
||
|
{
|
||
|
recalcAngle();
|
||
|
update();
|
||
|
QwtAbstractSlider::valueChange();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Determine the value corresponding to a specified position
|
||
|
|
||
|
Called by QwtAbstractSlider
|
||
|
\param p point
|
||
|
*/
|
||
|
double QwtKnob::getValue(const QPoint &p)
|
||
|
{
|
||
|
const double dx = double((rect().x() + rect().width() / 2) - p.x() );
|
||
|
const double dy = double((rect().y() + rect().height() / 2) - p.y() );
|
||
|
|
||
|
const double arc = atan2(-dx,dy) * 180.0 / M_PI;
|
||
|
|
||
|
double newValue = 0.5 * (minValue() + maxValue())
|
||
14 years ago
|
+ (arc + d_data->nTurns * 360.0) * (maxValue() - minValue())
|
||
|
/ d_data->totalAngle;
|
||
15 years ago
|
|
||
|
const double oneTurn = fabs(maxValue() - minValue()) * 360.0 / d_data->totalAngle;
|
||
|
const double eqValue = value() + mouseOffset();
|
||
|
|
||
14 years ago
|
if (fabs(newValue - eqValue) > 0.5 * oneTurn) {
|
||
15 years ago
|
if (newValue < eqValue)
|
||
14 years ago
|
newValue += oneTurn;
|
||
15 years ago
|
else
|
||
14 years ago
|
newValue -= oneTurn;
|
||
15 years ago
|
}
|
||
|
|
||
14 years ago
|
return newValue;
|
||
15 years ago
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Set the scrolling mode and direction
|
||
|
|
||
|
Called by QwtAbstractSlider
|
||
|
\param p Point in question
|
||
|
*/
|
||
|
void QwtKnob::getScrollMode(const QPoint &p, int &scrollMode, int &direction)
|
||
|
{
|
||
|
const int r = d_data->knobRect.width() / 2;
|
||
|
|
||
|
const int dx = d_data->knobRect.x() + r - p.x();
|
||
|
const int dy = d_data->knobRect.y() + r - p.y();
|
||
|
|
||
14 years ago
|
if ( (dx * dx) + (dy * dy) <= (r * r)) { // point is inside the knob
|
||
15 years ago
|
scrollMode = ScrMouse;
|
||
|
direction = 0;
|
||
14 years ago
|
} else { // point lies outside
|
||
15 years ago
|
scrollMode = ScrTimer;
|
||
|
double arc = atan2(double(-dx),double(dy)) * 180.0 / M_PI;
|
||
|
if ( arc < d_data->angle)
|
||
14 years ago
|
direction = -1;
|
||
15 years ago
|
else if (arc > d_data->angle)
|
||
14 years ago
|
direction = 1;
|
||
15 years ago
|
else
|
||
14 years ago
|
direction = 0;
|
||
15 years ago
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
\brief Notify a change of the range
|
||
|
|
||
|
Called by QwtAbstractSlider
|
||
|
*/
|
||
|
void QwtKnob::rangeChange()
|
||
|
{
|
||
|
if (autoScale())
|
||
|
rescale(minValue(), maxValue());
|
||
|
|
||
|
layoutKnob();
|
||
|
recalcAngle();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Qt Resize Event
|
||
|
*/
|
||
|
void QwtKnob::resizeEvent(QResizeEvent *)
|
||
|
{
|
||
|
layoutKnob( false );
|
||
|
}
|
||
|
|
||
|
//! Recalculate the knob's geometry and layout based on
|
||
|
// the current rect and fonts.
|
||
|
// \param update_geometry notify the layout system and call update
|
||
|
// to redraw the scale
|
||
|
void QwtKnob::layoutKnob( bool update_geometry )
|
||
|
{
|
||
|
const QRect r = rect();
|
||
|
const int radius = d_data->knobWidth / 2;
|
||
|
|
||
|
d_data->knobRect.setWidth(2 * radius);
|
||
|
d_data->knobRect.setHeight(2 * radius);
|
||
|
d_data->knobRect.moveCenter(r.center());
|
||
|
|
||
|
scaleDraw()->setRadius(radius + d_data->scaleDist);
|
||
|
scaleDraw()->moveCenter(r.center());
|
||
|
|
||
14 years ago
|
if ( update_geometry ) {
|
||
15 years ago
|
updateGeometry();
|
||
|
update();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Repaint the knob
|
||
|
*/
|
||
|
void QwtKnob::paintEvent(QPaintEvent *e)
|
||
|
{
|
||
|
const QRect &ur = e->rect();
|
||
14 years ago
|
if ( ur.isValid() ) {
|
||
15 years ago
|
#if QT_VERSION < 0x040000
|
||
|
QwtPaintBuffer paintBuffer(this, ur);
|
||
|
draw(paintBuffer.painter(), ur);
|
||
|
#else
|
||
|
QPainter painter(this);
|
||
|
painter.setRenderHint(QPainter::Antialiasing);
|
||
|
draw(&painter, ur);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Repaint the knob
|
||
|
*/
|
||
|
void QwtKnob::draw(QPainter *painter, const QRect& ur)
|
||
|
{
|
||
14 years ago
|
if ( !d_data->knobRect.contains( ur ) ) { // event from valueChange()
|
||
15 years ago
|
#if QT_VERSION < 0x040000
|
||
|
scaleDraw()->draw( painter, colorGroup() );
|
||
|
#else
|
||
|
scaleDraw()->draw( painter, palette() );
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
drawKnob( painter, d_data->knobRect );
|
||
|
|
||
|
if ( hasFocus() )
|
||
|
QwtPainter::drawFocusRect(painter, this);
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Draw the marker at the knob's front
|
||
|
\param p Painter
|
||
|
\param arc Angle of the marker
|
||
|
\param c Marker color
|
||
|
*/
|
||
|
void QwtKnob::drawMarker(QPainter *p, double arc, const QColor &c)
|
||
|
{
|
||
|
const double rarc = arc * M_PI / 180.0;
|
||
|
const double ca = cos(rarc);
|
||
|
const double sa = - sin(rarc);
|
||
|
|
||
|
int radius = d_data->knobRect.width() / 2 - d_data->borderWidth;
|
||
14 years ago
|
if (radius < 3)
|
||
|
radius = 3;
|
||
15 years ago
|
|
||
|
const int ym = d_data->knobRect.y() + radius + d_data->borderWidth;
|
||
|
const int xm = d_data->knobRect.x() + radius + d_data->borderWidth;
|
||
|
|
||
14 years ago
|
switch (d_data->symbol) {
|
||
|
case Dot: {
|
||
|
p->setBrush(c);
|
||
|
p->setPen(Qt::NoPen);
|
||
|
|
||
|
const double rb = double(qwtMax(radius - 4 - d_data->dotWidth / 2, 0));
|
||
|
p->drawEllipse(xm - qRound(sa * rb) - d_data->dotWidth / 2,
|
||
|
ym - qRound(ca * rb) - d_data->dotWidth / 2,
|
||
|
d_data->dotWidth, d_data->dotWidth);
|
||
|
break;
|
||
|
}
|
||
|
case Line: {
|
||
|
p->setPen(QPen(c, 2));
|
||
|
|
||
|
const double rb = qwtMax(double((radius - 4) / 3.0), 0.0);
|
||
|
const double re = qwtMax(double(radius - 4), 0.0);
|
||
|
|
||
|
p->drawLine ( xm - qRound(sa * rb), ym - qRound(ca * rb),
|
||
|
xm - qRound(sa * re), ym - qRound(ca * re));
|
||
|
|
||
|
break;
|
||
|
}
|
||
15 years ago
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Change the knob's width.
|
||
|
|
||
|
The specified width must be >= 5, or it will be clipped.
|
||
|
\param w New width
|
||
|
*/
|
||
|
void QwtKnob::setKnobWidth(int w)
|
||
|
{
|
||
|
d_data->knobWidth = qwtMax(w,5);
|
||
|
layoutKnob();
|
||
|
}
|
||
|
|
||
|
//! Return the width of the knob
|
||
14 years ago
|
int QwtKnob::knobWidth() const
|
||
15 years ago
|
{
|
||
|
return d_data->knobWidth;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Set the knob's border width
|
||
|
\param bw new border width
|
||
|
*/
|
||
|
void QwtKnob::setBorderWidth(int bw)
|
||
|
{
|
||
|
d_data->borderWidth = qwtMax(bw, 0);
|
||
|
layoutKnob();
|
||
|
}
|
||
|
|
||
|
//! Return the border width
|
||
14 years ago
|
int QwtKnob::borderWidth() const
|
||
15 years ago
|
{
|
||
|
return d_data->borderWidth;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Recalculate the marker angle corresponding to the
|
||
|
current value
|
||
|
*/
|
||
|
void QwtKnob::recalcAngle()
|
||
|
{
|
||
|
//
|
||
|
// calculate the angle corresponding to the value
|
||
|
//
|
||
14 years ago
|
if (maxValue() == minValue()) {
|
||
15 years ago
|
d_data->angle = 0;
|
||
|
d_data->nTurns = 0;
|
||
14 years ago
|
} else {
|
||
15 years ago
|
d_data->angle = (value() - 0.5 * (minValue() + maxValue()))
|
||
14 years ago
|
/ (maxValue() - minValue()) * d_data->totalAngle;
|
||
15 years ago
|
d_data->nTurns = floor((d_data->angle + 180.0) / 360.0);
|
||
|
d_data->angle = d_data->angle - d_data->nTurns * 360.0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
Recalculates the layout
|
||
|
\sa layoutKnob()
|
||
|
*/
|
||
|
void QwtKnob::scaleChange()
|
||
|
{
|
||
|
layoutKnob();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Recalculates the layout
|
||
|
\sa layoutKnob()
|
||
|
*/
|
||
|
void QwtKnob::fontChange(const QFont &f)
|
||
|
{
|
||
|
QwtAbstractSlider::fontChange( f );
|
||
|
layoutKnob();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\return minimumSizeHint()
|
||
|
*/
|
||
|
QSize QwtKnob::sizeHint() const
|
||
|
{
|
||
|
return minimumSizeHint();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Return a minimum size hint
|
||
14 years ago
|
\warning The return value of QwtKnob::minimumSizeHint() depends on the
|
||
15 years ago
|
font and the scale.
|
||
|
*/
|
||
|
QSize QwtKnob::minimumSizeHint() const
|
||
|
{
|
||
|
// Add the scale radial thickness to the knobWidth
|
||
|
const int sh = scaleDraw()->extent( QPen(), font() );
|
||
|
const int d = 2 * sh + 2 * d_data->scaleDist + d_data->knobWidth;
|
||
|
|
||
|
return QSize( d, d );
|
||
|
}
|