qwt_dial.cpp
/******************************************************************************
* 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 "qwt_dial.h"
#include "qwt_dial_needle.h"
#include "qwt_math.h"
#include "qwt_scale_map.h"
#include "qwt_round_scale_draw.h"
#include "qwt_painter.h"
#include "qwt.h"
#include <qpainter.h>
#include <qpalette.h>
#include <qpixmap.h>
#include <qevent.h>
#include <qstyle.h>
#include <qstyleoption.h>
static inline double qwtAngleDist( double a1, double a2 )
{
double dist = qAbs( a2 - a1 );
if ( dist > 360.0 )
dist -= 360.0;
return dist;
}
static inline bool qwtIsOnArc( double angle, double min, double max )
{
if ( min < max )
{
return ( angle >= min ) && ( angle <= max );
}
else
{
return ( angle >= min ) || ( angle <= max );
}
}
static inline double qwtBoundedAngle( double min, double angle, double max )
{
double from = qwtNormalizeDegrees( min );
double to = qwtNormalizeDegrees( max );
double a;
if ( qwtIsOnArc( angle, from, to ) )
{
a = angle;
if ( a < min )
a += 360.0;
}
else
{
if ( qwtAngleDist( angle, from ) <
qwtAngleDist( angle, to ) )
{
a = min;
}
else
{
a = max;
}
}
return a;
}
class QwtDial::PrivateData
{
public:
PrivateData()
: frameShadow( Sunken )
, lineWidth( 0 )
, mode( RotateNeedle )
, origin( 90.0 )
, minScaleArc( 0.0 )
, maxScaleArc( 0.0 )
, needle( NULL )
, arcOffset( 0.0 )
, mouseOffset( 0.0 )
{
}
~PrivateData()
{
delete needle;
}
Shadow frameShadow;
int lineWidth;
QwtDial::Mode mode;
double origin;
double minScaleArc;
double maxScaleArc;
QwtDialNeedle* needle;
double arcOffset;
double mouseOffset;
QPixmap pixmapCache;
};
QwtDial::QwtDial( QWidget* parent )
: QwtAbstractSlider( parent )
{
m_data = new PrivateData;
setFocusPolicy( Qt::TabFocus );
QPalette p = palette();
for ( int i = 0; i < QPalette::NColorGroups; i++ )
{
const QPalette::ColorGroup colorGroup =
static_cast< QPalette::ColorGroup >( i );
// Base: background color of the circle inside the frame.
// WindowText: background color of the circle inside the scale
p.setColor( colorGroup, QPalette::WindowText,
p.color( colorGroup, QPalette::Base ) );
}
setPalette( p );
QwtRoundScaleDraw* scaleDraw = new QwtRoundScaleDraw();
scaleDraw->setRadius( 0 );
setScaleDraw( scaleDraw );
setScaleArc( 0.0, 360.0 ); // scale as a full circle
setScaleMaxMajor( 10 );
setScaleMaxMinor( 5 );
setValue( 0.0 );
}
QwtDial::~QwtDial()
{
delete m_data;
}
void QwtDial::setFrameShadow( Shadow shadow )
{
if ( shadow != m_data->frameShadow )
{
invalidateCache();
m_data->frameShadow = shadow;
if ( lineWidth() > 0 )
update();
}
}
QwtDial::Shadow QwtDial::frameShadow() const
{
return m_data->frameShadow;
}
void QwtDial::setLineWidth( int lineWidth )
{
if ( lineWidth < 0 )
lineWidth = 0;
if ( m_data->lineWidth != lineWidth )
{
invalidateCache();
m_data->lineWidth = lineWidth;
update();
}
}
int QwtDial::lineWidth() const
{
return m_data->lineWidth;
}
QRect QwtDial::innerRect() const
{
const int lw = lineWidth();
return boundingRect().adjusted( lw, lw, -lw, -lw );
}
QRect QwtDial::boundingRect() const
{
const QRect cr = contentsRect();
const int dim = qMin( cr.width(), cr.height() );
QRect inner( 0, 0, dim, dim );
inner.moveCenter( cr.center() );
return inner;
}
QRect QwtDial::scaleInnerRect() const
{
QRect rect = innerRect();
const QwtAbstractScaleDraw* sd = scaleDraw();
if ( sd )
{
int scaleDist = qwtCeil( sd->extent( font() ) );
scaleDist++; // margin
rect.adjust( scaleDist, scaleDist, -scaleDist, -scaleDist );
}
return rect;
}
void QwtDial::setMode( Mode mode )
{
if ( mode != m_data->mode )
{
invalidateCache();
m_data->mode = mode;
sliderChange();
}
}
QwtDial::Mode QwtDial::mode() const
{
return m_data->mode;
}
void QwtDial::invalidateCache()
{
m_data->pixmapCache = QPixmap();
}
void QwtDial::paintEvent( QPaintEvent* event )
{
QPainter painter( this );
painter.setClipRegion( event->region() );
QStyleOption opt;
opt.initFrom(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
if ( m_data->mode == QwtDial::RotateScale )
{
painter.save();
painter.setRenderHint( QPainter::Antialiasing, true );
drawContents( &painter );
painter.restore();
}
const QRect r = contentsRect();
if ( r.size() != m_data->pixmapCache.size() )
{
m_data->pixmapCache = QwtPainter::backingStore( this, r.size() );
m_data->pixmapCache.fill( Qt::transparent );
QPainter p( &m_data->pixmapCache );
p.setRenderHint( QPainter::Antialiasing, true );
p.translate( -r.topLeft() );
if ( m_data->mode != QwtDial::RotateScale )
drawContents( &p );
if ( lineWidth() > 0 )
drawFrame( &p );
if ( m_data->mode != QwtDial::RotateNeedle )
drawNeedle( &p );
}
painter.drawPixmap( r.topLeft(), m_data->pixmapCache );
if ( m_data->mode == QwtDial::RotateNeedle )
drawNeedle( &painter );
if ( hasFocus() )
drawFocusIndicator( &painter );
}
void QwtDial::drawFocusIndicator( QPainter* painter ) const
{
QwtPainter::drawFocusRect( painter, this, boundingRect() );
}
void QwtDial::drawFrame( QPainter* painter )
{
QwtPainter::drawRoundFrame( painter, boundingRect(),
palette(), lineWidth(), m_data->frameShadow );
}
void QwtDial::drawContents( QPainter* painter ) const
{
if ( testAttribute( Qt::WA_NoSystemBackground ) ||
palette().brush( QPalette::Base ) !=
palette().brush( QPalette::Window ) )
{
const QRectF br = boundingRect();
painter->save();
painter->setPen( Qt::NoPen );
painter->setBrush( palette().brush( QPalette::Base ) );
painter->drawEllipse( br );
painter->restore();
}
const QRectF insideScaleRect = scaleInnerRect();
if ( palette().brush( QPalette::WindowText ) !=
palette().brush( QPalette::Base ) )
{
painter->save();
painter->setPen( Qt::NoPen );
painter->setBrush( palette().brush( QPalette::WindowText ) );
painter->drawEllipse( insideScaleRect );
painter->restore();
}
const QPointF center = insideScaleRect.center();
const double radius = 0.5 * insideScaleRect.width();
painter->save();
drawScale( painter, center, radius );
painter->restore();
painter->save();
drawScaleContents( painter, center, radius );
painter->restore();
}
void QwtDial::drawNeedle( QPainter* painter, const QPointF& center,
double radius, double direction, QPalette::ColorGroup colorGroup ) const
{
if ( m_data->needle )
{
direction = 360.0 - direction; // counter clockwise
m_data->needle->draw( painter, center, radius, direction, colorGroup );
}
}
void QwtDial::drawNeedle( QPainter* painter ) const
{
if ( !isValid() )
return;
QPalette::ColorGroup colorGroup;
if ( isEnabled() )
colorGroup = hasFocus() ? QPalette::Active : QPalette::Inactive;
else
colorGroup = QPalette::Disabled;
const QRectF sr = scaleInnerRect();
painter->save();
painter->setRenderHint( QPainter::Antialiasing, true );
drawNeedle( painter, sr.center(), 0.5 * sr.width(),
scaleMap().transform( value() ) + 270.0, colorGroup );
painter->restore();
}
void QwtDial::drawScale( QPainter* painter,
const QPointF& center, double radius ) const
{
QwtRoundScaleDraw* sd = const_cast< QwtRoundScaleDraw* >( scaleDraw() );
if ( sd == NULL )
return;
sd->setRadius( radius );
sd->moveCenter( center );
QPalette pal = palette();
const QColor textColor = pal.color( QPalette::Text );
pal.setColor( QPalette::WindowText, textColor ); // ticks, backbone
painter->setFont( font() );
painter->setPen( QPen( textColor, sd->penWidthF() ) );
painter->setBrush( Qt::red );
sd->draw( painter, pal );
}
void QwtDial::drawScaleContents( QPainter* painter,
const QPointF& center, double radius ) const
{
Q_UNUSED(painter);
Q_UNUSED(center);
Q_UNUSED(radius);
}
void QwtDial::setNeedle( QwtDialNeedle* needle )
{
if ( needle != m_data->needle )
{
if ( m_data->needle )
delete m_data->needle;
m_data->needle = needle;
update();
}
}
const QwtDialNeedle* QwtDial::needle() const
{
return m_data->needle;
}
QwtDialNeedle* QwtDial::needle()
{
return m_data->needle;
}
QwtRoundScaleDraw* QwtDial::scaleDraw()
{
return static_cast< QwtRoundScaleDraw* >( abstractScaleDraw() );
}
const QwtRoundScaleDraw* QwtDial::scaleDraw() const
{
return static_cast< const QwtRoundScaleDraw* >( abstractScaleDraw() );
}
void QwtDial::setScaleDraw( QwtRoundScaleDraw* scaleDraw )
{
setAbstractScaleDraw( scaleDraw );
sliderChange();
}
void QwtDial::setScaleArc( double minArc, double maxArc )
{
if ( minArc != 360.0 && minArc != -360.0 )
minArc = std::fmod( minArc, 360.0 );
if ( maxArc != 360.0 && maxArc != -360.0 )
maxArc = std::fmod( maxArc, 360.0 );
double minScaleArc = qwtMinF( minArc, maxArc );
double maxScaleArc = qwtMaxF( minArc, maxArc );
if ( maxScaleArc - minScaleArc > 360.0 )
maxScaleArc = minScaleArc + 360.0;
if ( ( minScaleArc != m_data->minScaleArc ) ||
( maxScaleArc != m_data->maxScaleArc ) )
{
m_data->minScaleArc = minScaleArc;
m_data->maxScaleArc = maxScaleArc;
invalidateCache();
sliderChange();
}
}
void QwtDial::setMinScaleArc( double min )
{
setScaleArc( min, m_data->maxScaleArc );
}
double QwtDial::minScaleArc() const
{
return m_data->minScaleArc;
}
void QwtDial::setMaxScaleArc( double max )
{
setScaleArc( m_data->minScaleArc, max );
}
double QwtDial::maxScaleArc() const
{
return m_data->maxScaleArc;
}
void QwtDial::setOrigin( double origin )
{
invalidateCache();
m_data->origin = origin;
sliderChange();
}
double QwtDial::origin() const
{
return m_data->origin;
}
QSize QwtDial::sizeHint() const
{
int sh = 0;
if ( scaleDraw() )
sh = qwtCeil( scaleDraw()->extent( font() ) );
const int d = 6 * sh + 2 * lineWidth();
QSize hint( d, d );
if ( !isReadOnly() )
hint = qwtExpandedToGlobalStrut( hint );
return hint;
}
QSize QwtDial::minimumSizeHint() const
{
int sh = 0;
if ( scaleDraw() )
sh = qwtCeil( scaleDraw()->extent( font() ) );
const int d = 3 * sh + 2 * lineWidth();
return QSize( d, d );
}
bool QwtDial::isScrollPosition( const QPoint& pos ) const
{
const QRegion region( innerRect(), QRegion::Ellipse );
if ( region.contains( pos ) && ( pos != innerRect().center() ) )
{
double angle = QLineF( rect().center(), pos ).angle();
if ( m_data->mode == QwtDial::RotateScale )
angle = 360.0 - angle;
double valueAngle =
qwtNormalizeDegrees( 90.0 - scaleMap().transform( value() ) );
m_data->mouseOffset = qwtNormalizeDegrees( angle - valueAngle );
m_data->arcOffset = scaleMap().p1();
return true;
}
return false;
}
double QwtDial::scrolledTo( const QPoint& pos ) const
{
double angle = QLineF( rect().center(), pos ).angle();
if ( m_data->mode == QwtDial::RotateScale )
{
angle += scaleMap().p1() - m_data->arcOffset;
angle = 360.0 - angle;
}
angle = qwtNormalizeDegrees( angle - m_data->mouseOffset );
angle = qwtNormalizeDegrees( 90.0 - angle );
if ( scaleMap().pDist() >= 360.0 )
{
if ( angle < scaleMap().p1() )
angle += 360.0;
if ( !wrapping() )
{
double boundedAngle = angle;
const double arc = angle - scaleMap().transform( value() );
if ( qAbs( arc ) > 180.0 )
{
boundedAngle = ( arc > 0 )
? scaleMap().p1() : scaleMap().p2();
}
m_data->mouseOffset += ( boundedAngle - angle );
angle = boundedAngle;
}
}
else
{
const double boundedAngle =
qwtBoundedAngle( scaleMap().p1(), angle, scaleMap().p2() );
if ( !wrapping() )
m_data->mouseOffset += ( boundedAngle - angle );
angle = boundedAngle;
}
return scaleMap().invTransform( angle );
}
void QwtDial::changeEvent( QEvent* event )
{
switch( event->type() )
{
case QEvent::EnabledChange:
case QEvent::FontChange:
case QEvent::StyleChange:
case QEvent::PaletteChange:
case QEvent::LanguageChange:
case QEvent::LocaleChange:
{
invalidateCache();
break;
}
default:
break;
}
QwtAbstractSlider::changeEvent( event );
}
void QwtDial::wheelEvent( QWheelEvent* event )
{
#if QT_VERSION < 0x050e00
const QPoint wheelPos = event->pos();
#else
const QPoint wheelPos = event->position().toPoint();
#endif
const QRegion region( innerRect(), QRegion::Ellipse );
if ( region.contains( wheelPos ) )
QwtAbstractSlider::wheelEvent( event );
}
void QwtDial::setAngleRange( double angle, double span )
{
if ( QwtRoundScaleDraw* sd = scaleDraw() )
{
angle = qwtNormalizeDegrees( angle - 270.0 );
sd->setAngleRange( angle, angle + span );
}
}
void QwtDial::scaleChange()
{
invalidateCache();
QwtAbstractSlider::scaleChange();
}
void QwtDial::sliderChange()
{
setAngleRange( m_data->origin + m_data->minScaleArc,
m_data->maxScaleArc - m_data->minScaleArc );
if ( mode() == RotateScale )
{
const double arc = scaleMap().transform( value() ) - scaleMap().p1();
setAngleRange( m_data->origin - arc,
m_data->maxScaleArc - m_data->minScaleArc );
}
QwtAbstractSlider::sliderChange();
}
#if QWT_MOC_INCLUDE
#include "moc_qwt_dial.cpp"
#endif
QwtAbstractScaleDraw
A abstract base class for drawing scales.
Definition: qwt_abstract_scale_draw.h:32
QwtAbstractScaleDraw::extent
virtual double extent(const QFont &font) const =0
QwtAbstractScaleDraw::draw
virtual void draw(QPainter *, const QPalette &) const
Draw the scale.
Definition: qwt_abstract_scale_draw.cpp:169
QwtAbstractScaleDraw::penWidthF
qreal penWidthF() const
Definition: qwt_abstract_scale_draw.cpp:156
QwtAbstractScale::scaleMap
const QwtScaleMap & scaleMap() const
Definition: qwt_abstract_scale.cpp:357
QwtAbstractScale::setScaleMaxMajor
void setScaleMaxMajor(int ticks)
Set the maximum number of major tick intervals.
Definition: qwt_abstract_scale.cpp:189
QwtAbstractScale::abstractScaleDraw
const QwtAbstractScaleDraw * abstractScaleDraw() const
Definition: qwt_abstract_scale.cpp:302
QwtAbstractScale::setScaleMaxMinor
void setScaleMaxMinor(int ticks)
Set the maximum number of minor tick intervals.
Definition: qwt_abstract_scale.cpp:219
QwtAbstractScale::transform
int transform(double) const
Definition: qwt_abstract_scale.cpp:369
QwtAbstractScale::setAbstractScaleDraw
void setAbstractScaleDraw(QwtAbstractScaleDraw *)
Set a scale draw.
Definition: qwt_abstract_scale.cpp:277
QwtAbstractScale::changeEvent
virtual void changeEvent(QEvent *) override
Definition: qwt_abstract_scale.cpp:453
QwtAbstractSlider
An abstract base class for slider widgets with a scale.
Definition: qwt_abstract_slider.h:33
QwtAbstractSlider::scaleChange
virtual void scaleChange() override
Definition: qwt_abstract_slider.cpp:811
QwtAbstractSlider::sliderChange
virtual void sliderChange()
Calling update()
Definition: qwt_abstract_slider.cpp:829
QwtAbstractSlider::setValue
void setValue(double value)
Definition: qwt_abstract_slider.cpp:570
QwtAbstractSlider::wrapping
bool wrapping() const
Definition: qwt_abstract_slider.cpp:608
QwtAbstractSlider::isReadOnly
bool isReadOnly() const
Definition: qwt_abstract_slider.cpp:159
QwtAbstractSlider::isValid
bool isValid() const
Definition: qwt_abstract_slider.cpp:125
QwtAbstractSlider::wheelEvent
virtual void wheelEvent(QWheelEvent *) override
Definition: qwt_abstract_slider.cpp:296
QwtAbstractSlider::value
double value() const
Returns the current value.
Definition: qwt_abstract_slider.cpp:587
QwtDial::setMinScaleArc
void setMinScaleArc(double)
Definition: qwt_dial.cpp:618
QwtDial::drawFrame
virtual void drawFrame(QPainter *)
Definition: qwt_dial.cpp:373
QwtDial::minScaleArc
double minScaleArc() const
Definition: qwt_dial.cpp:627
QwtDial::~QwtDial
virtual ~QwtDial()
Destructor.
Definition: qwt_dial.cpp:159
QwtDial::maxScaleArc
double maxScaleArc() const
Definition: qwt_dial.cpp:647
QwtDial::setFrameShadow
void setFrameShadow(Shadow)
Definition: qwt_dial.cpp:170
QwtDial::wheelEvent
virtual void wheelEvent(QWheelEvent *) override
Definition: qwt_dial.cpp:829
QwtDial::sizeHint
virtual QSize sizeHint() const override
Definition: qwt_dial.cpp:683
QwtDial::setScaleDraw
void setScaleDraw(QwtRoundScaleDraw *)
Definition: qwt_dial.cpp:574
QwtDial::scaleInnerRect
virtual QRect scaleInnerRect() const
Definition: qwt_dial.cpp:250
QwtDial::setOrigin
virtual void setOrigin(double)
Change the origin.
Definition: qwt_dial.cpp:660
QwtDial::changeEvent
virtual void changeEvent(QEvent *) override
Definition: qwt_dial.cpp:804
QwtDial::scaleChange
virtual void scaleChange() override
Definition: qwt_dial.cpp:855
QwtDial::origin
double origin() const
Definition: qwt_dial.cpp:674
QwtDial::boundingRect
QRect boundingRect() const
Definition: qwt_dial.cpp:234
QwtDial::drawScale
virtual void drawScale(QPainter *, const QPointF &center, double radius) const
Definition: qwt_dial.cpp:475
QwtDial::needle
const QwtDialNeedle * needle() const
Definition: qwt_dial.cpp:538
QwtDial::setMode
void setMode(Mode)
Change the mode of the dial.
Definition: qwt_dial.cpp:278
QwtDial::Mode
Mode
Mode controlling whether the needle or the scale is rotating.
Definition: qwt_dial.h:87
QwtDial::RotateScale
@ RotateScale
The needle is fixed, the scales are rotating.
Definition: qwt_dial.h:92
QwtDial::RotateNeedle
@ RotateNeedle
The needle is rotating.
Definition: qwt_dial.h:89
QwtDial::Shadow
Shadow
Frame shadow.
Definition: qwt_dial.h:74
QwtDial::Sunken
@ Sunken
QFrame::Sunken.
Definition: qwt_dial.h:82
QwtDial::setLineWidth
void setLineWidth(int)
Definition: qwt_dial.cpp:197
QwtDial::isScrollPosition
virtual bool isScrollPosition(const QPoint &) const override
Determine what to do when the user presses a mouse button.
Definition: qwt_dial.cpp:721
QwtDial::mode
Mode mode() const
Definition: qwt_dial.cpp:293
QwtDial::scrolledTo
virtual double scrolledTo(const QPoint &) const override
Determine the value for a new position of the slider handle.
Definition: qwt_dial.cpp:751
QwtDial::invalidateCache
void invalidateCache()
Definition: qwt_dial.cpp:301
QwtDial::lineWidth
int lineWidth() const
Definition: qwt_dial.cpp:215
QwtDial::QwtDial
QwtDial(QWidget *parent=NULL)
Constructor.
Definition: qwt_dial.cpp:124
QwtDial::drawFocusIndicator
virtual void drawFocusIndicator(QPainter *) const
Definition: qwt_dial.cpp:362
QwtDial::sliderChange
virtual void sliderChange() override
Calling update()
Definition: qwt_dial.cpp:861
QwtDial::minimumSizeHint
virtual QSize minimumSizeHint() const override
Definition: qwt_dial.cpp:702
QwtDial::frameShadow
Shadow frameShadow() const
Definition: qwt_dial.cpp:186
QwtDial::paintEvent
virtual void paintEvent(QPaintEvent *) override
Definition: qwt_dial.cpp:310
QwtDial::setNeedle
void setNeedle(QwtDialNeedle *)
Definition: qwt_dial.cpp:522
QwtDial::drawNeedle
virtual void drawNeedle(QPainter *, const QPointF &, double radius, double direction, QPalette::ColorGroup) const
Definition: qwt_dial.cpp:438
QwtDial::setScaleArc
void setScaleArc(double minArc, double maxArc)
Definition: qwt_dial.cpp:588
QwtDial::scaleDraw
QwtRoundScaleDraw * scaleDraw()
Definition: qwt_dial.cpp:553
QwtDial::drawScaleContents
virtual void drawScaleContents(QPainter *painter, const QPointF &center, double radius) const
Definition: qwt_dial.cpp:506
QwtDial::innerRect
QRect innerRect() const
Definition: qwt_dial.cpp:224
QwtDial::drawContents
virtual void drawContents(QPainter *) const
Draw the contents inside the frame.
Definition: qwt_dial.cpp:391
QwtDial::setMaxScaleArc
void setMaxScaleArc(double)
Definition: qwt_dial.cpp:638
QwtDialNeedle
Base class for needles that can be used in a QwtDial.
Definition: qwt_dial_needle.h:28
QwtPainter::drawRoundFrame
static void drawRoundFrame(QPainter *, const QRectF &, const QPalette &, int lineWidth, int frameStyle)
Definition: qwt_painter.cpp:845
QwtPainter::drawFocusRect
static void drawFocusRect(QPainter *, const QWidget *)
Draw a focus rectangle on a widget using its style.
Definition: qwt_painter.cpp:815
QwtPainter::backingStore
static QPixmap backingStore(QWidget *, const QSize &)
Definition: qwt_painter.cpp:1525
QwtRoundScaleDraw
A class for drawing round scales.
Definition: qwt_round_scale_draw.h:32
QwtRoundScaleDraw::setRadius
void setRadius(double radius)
Definition: qwt_round_scale_draw.cpp:66
QwtRoundScaleDraw::moveCenter
void moveCenter(double x, double y)
Move the center of the scale draw, leaving the radius unchanged.
Definition: qwt_round_scale_draw.h:64
QwtScaleMap::p1
double p1() const
Definition: qwt_scale_map.h:99
QwtScaleMap::transform
double transform(double s) const
Definition: qwt_scale_map.h:137
QwtScaleMap::invTransform
double invTransform(double p) const
Definition: qwt_scale_map.h:154
QwtScaleMap::p2
double p2() const
Definition: qwt_scale_map.h:107