12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190 |
- /* -*- 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 "qwt_dial.h"
- #include "qwt_dial_needle.h"
- #include "qwt_math.h"
- #include "qwt_scale_engine.h"
- #include "qwt_scale_map.h"
- #include "qwt_painter.h"
- #include <qpainter.h>
- #include <qbitmap.h>
- #include <qpalette.h>
- #include <qpixmap.h>
- #include <qevent.h>
- #include <qalgorithms.h>
- #include <qmath.h>
- #if QT_VERSION < 0x040601
- #define qAtan(x) ::atan(x)
- #endif
- class QwtDial::PrivateData
- {
- public:
- PrivateData():
- visibleBackground( true ),
- frameShadow( Sunken ),
- lineWidth( 0 ),
- mode( RotateNeedle ),
- direction( Clockwise ),
- origin( 90.0 ),
- minScaleArc( 0.0 ),
- maxScaleArc( 0.0 ),
- scaleDraw( 0 ),
- maxMajIntv( 36 ),
- maxMinIntv( 10 ),
- scaleStep( 0.0 ),
- needle( 0 )
- {
- }
- ~PrivateData()
- {
- delete scaleDraw;
- delete needle;
- }
- bool visibleBackground;
- Shadow frameShadow;
- int lineWidth;
- QwtDial::Mode mode;
- QwtDial::Direction direction;
- double origin;
- double minScaleArc;
- double maxScaleArc;
- QwtDialScaleDraw *scaleDraw;
- int maxMajIntv;
- int maxMinIntv;
- double scaleStep;
- QwtDialNeedle *needle;
- static double previousDir;
- };
- double QwtDial::PrivateData::previousDir = -1.0;
- /*!
- Constructor
- \param parent Parent dial widget
- */
- QwtDialScaleDraw::QwtDialScaleDraw( QwtDial *parent ):
- d_parent( parent ),
- d_penWidth( 1.0 )
- {
- }
- /*!
- Set the pen width used for painting the scale
- \param penWidth Pen width
- \sa penWidth(), QwtDial::drawScale()
- */
- void QwtDialScaleDraw::setPenWidth( double penWidth )
- {
- d_penWidth = qMax( penWidth, 0.0 );
- }
- /*!
- \return Pen width used for painting the scale
- \sa setPenWidth, QwtDial::drawScale()
- */
- double QwtDialScaleDraw::penWidth() const
- {
- return d_penWidth;
- }
- /*!
- Call QwtDial::scaleLabel of the parent dial widget.
- \param value Value to display
- \sa QwtDial::scaleLabel()
- */
- QwtText QwtDialScaleDraw::label( double value ) const
- {
- if ( d_parent == NULL )
- return QwtRoundScaleDraw::label( value );
- return d_parent->scaleLabel( value );
- }
- /*!
- \brief Constructor
- \param parent Parent widget
- Create a dial widget with no scale and no needle.
- The default origin is 90.0 with no valid value. It accepts
- mouse and keyboard inputs and has no step size. The default mode
- is QwtDial::RotateNeedle.
- */
- QwtDial::QwtDial( QWidget* parent ):
- QwtAbstractSlider( Qt::Horizontal, parent )
- {
- initDial();
- }
- void QwtDial::initDial()
- {
- d_data = new PrivateData;
- setFocusPolicy( Qt::TabFocus );
- QPalette p = palette();
- for ( int i = 0; i < QPalette::NColorGroups; i++ )
- {
- const QPalette::ColorGroup cg = ( QPalette::ColorGroup )i;
- // Base: background color of the circle inside the frame.
- // WindowText: background color of the circle inside the scale
- p.setColor( cg, QPalette::WindowText,
- p.color( cg, QPalette::Base ) );
- }
- setPalette( p );
- d_data->scaleDraw = new QwtDialScaleDraw( this );
- d_data->scaleDraw->setRadius( 0 );
- setScaleArc( 0.0, 360.0 ); // scale as a full circle
- setRange( 0.0, 360.0, 1.0, 10 ); // degrees as deafult
- }
- //! Destructor
- QwtDial::~QwtDial()
- {
- delete d_data;
- }
- /*!
- Show/Hide the area outside of the frame
- \param show Show if true, hide if false
- \sa hasVisibleBackground(), setMask()
- \warning When QwtDial is a toplevel widget the window
- border might disappear too.
- */
- void QwtDial::showBackground( bool show )
- {
- if ( d_data->visibleBackground != show )
- {
- d_data->visibleBackground = show;
- updateMask();
- }
- }
- /*!
- true when the area outside of the frame is visible
- \sa showBackground(), setMask()
- */
- bool QwtDial::hasVisibleBackground() const
- {
- return d_data->visibleBackground;
- }
- /*!
- Sets the frame shadow value from the frame style.
- \param shadow Frame shadow
- \sa setLineWidth(), QFrame::setFrameShadow()
- */
- void QwtDial::setFrameShadow( Shadow shadow )
- {
- if ( shadow != d_data->frameShadow )
- {
- d_data->frameShadow = shadow;
- if ( lineWidth() > 0 )
- update();
- }
- }
- /*!
- \return Frame shadow
- /sa setFrameShadow(), lineWidth(), QFrame::frameShadow
- */
- QwtDial::Shadow QwtDial::frameShadow() const
- {
- return d_data->frameShadow;
- }
- /*!
- Sets the line width
- \param lineWidth Line width
- \sa setFrameShadow()
- */
- void QwtDial::setLineWidth( int lineWidth )
- {
- if ( lineWidth < 0 )
- lineWidth = 0;
- if ( d_data->lineWidth != lineWidth )
- {
- d_data->lineWidth = lineWidth;
- update();
- }
- }
- /*!
- \return Line width of the frame
- \sa setLineWidth(), frameShadow(), lineWidth()
- */
- int QwtDial::lineWidth() const
- {
- return d_data->lineWidth;
- }
- /*!
- \return bounding rect of the circle inside the frame
- \sa setLineWidth(), scaleContentsRect(), boundingRect()
- */
- QRect QwtDial::contentsRect() const
- {
- const int lw = lineWidth();
- QRect r = boundingRect();
- if ( lw > 0 )
- {
- r.setRect( r.x() + lw, r.y() + lw,
- r.width() - 2 * lw, r.height() - 2 * lw );
- }
- return r;
- }
- /*!
- \return bounding rect of the dial including the frame
- \sa setLineWidth(), scaleContentsRect(), contentsRect()
- */
- QRect QwtDial::boundingRect() const
- {
- const int radius = qMin( width(), height() ) / 2;
- QRect r( 0, 0, 2 * radius, 2 * radius );
- r.moveCenter( rect().center() );
- return r;
- }
- /*!
- \return rect inside the scale
- \sa setLineWidth(), boundingRect(), contentsRect()
- */
- QRect QwtDial::scaleContentsRect() const
- {
- const QPen scalePen( palette().text(), 0, Qt::NoPen );
- int scaleDist = 0;
- if ( d_data->scaleDraw )
- {
- scaleDist = qCeil( d_data->scaleDraw->extent( font() ) );
- scaleDist++; // margin
- }
- const QRect rect = contentsRect();
- return QRect( rect.x() + scaleDist, rect.y() + scaleDist,
- rect.width() - 2 * scaleDist, rect.height() - 2 * scaleDist );
- }
- /*!
- \brief Change the mode of the meter.
- \param mode New mode
- The value of the meter is indicated by the difference
- between north of the scale and the direction of the needle.
- In case of QwtDial::RotateNeedle north is pointing
- to the origin() and the needle is rotating, in case of
- QwtDial::RotateScale, the needle points to origin()
- and the scale is rotating.
- The default mode is QwtDial::RotateNeedle.
- \sa mode(), setValue(), setOrigin()
- */
- void QwtDial::setMode( Mode mode )
- {
- if ( mode != d_data->mode )
- {
- d_data->mode = mode;
- update();
- }
- }
- /*!
- \return mode of the dial.
- The value of the dial is indicated by the difference
- between the origin and the direction of the needle.
- In case of QwtDial::RotateNeedle the scale arc is fixed
- to the origin() and the needle is rotating, in case of
- QwtDial::RotateScale, the needle points to origin()
- and the scale is rotating.
- The default mode is QwtDial::RotateNeedle.
- \sa setMode(), origin(), setScaleArc(), value()
- */
- QwtDial::Mode QwtDial::mode() const
- {
- return d_data->mode;
- }
- /*!
- Sets whether it is possible to step the value from the highest value to
- the lowest value and vice versa to on.
- \param wrapping en/disables wrapping
- \sa wrapping(), QwtDoubleRange::periodic()
- \note The meaning of wrapping is like the wrapping property of QSpinBox,
- but not like it is used in QDial.
- */
- void QwtDial::setWrapping( bool wrapping )
- {
- setPeriodic( wrapping );
- }
- /*!
- wrapping() holds whether it is possible to step the value from the
- highest value to the lowest value and vice versa.
- \sa setWrapping(), QwtDoubleRange::setPeriodic()
- \note The meaning of wrapping is like the wrapping property of QSpinBox,
- but not like it is used in QDial.
- */
- bool QwtDial::wrapping() const
- {
- return periodic();
- }
- /*!
- Set the direction of the dial (clockwise/counterclockwise)
- Direction direction
- \sa direction()
- */
- void QwtDial::setDirection( Direction direction )
- {
- if ( direction != d_data->direction )
- {
- d_data->direction = direction;
- update();
- }
- }
- /*!
- \return Direction of the dial
- The default direction of a dial is QwtDial::Clockwise
- \sa setDirection()
- */
- QwtDial::Direction QwtDial::direction() const
- {
- return d_data->direction;
- }
- /*!
- Resize the dial widget
- \param e Resize event
- */
- void QwtDial::resizeEvent( QResizeEvent *e )
- {
- QWidget::resizeEvent( e );
- if ( !hasVisibleBackground() )
- updateMask();
- }
- /*!
- Paint the dial
- \param e Paint event
- */
- void QwtDial::paintEvent( QPaintEvent *e )
- {
- const QRect &ur = e->rect();
- if ( ur.isValid() )
- {
- QPainter painter( this );
- painter.setRenderHint( QPainter::Antialiasing, true );
- painter.save();
- drawContents( &painter );
- painter.restore();
- painter.save();
- drawFrame( &painter );
- painter.restore();
- if ( hasFocus() )
- drawFocusIndicator( &painter );
- }
- }
- /*!
- Draw a dotted round circle, if !isReadOnly()
- \param painter Painter
- */
- void QwtDial::drawFocusIndicator( QPainter *painter ) const
- {
- if ( !isReadOnly() )
- {
- QRect focusRect = contentsRect();
- const int margin = 2;
- focusRect.setRect(
- focusRect.x() + margin,
- focusRect.y() + margin,
- focusRect.width() - 2 * margin,
- focusRect.height() - 2 * margin );
- QColor color = palette().color( QPalette::Base );
- if ( color.isValid() )
- {
- const QColor gray( Qt::gray );
- int h, s, v;
- color.getHsv( &h, &s, &v );
- color = ( v > 128 ) ? gray.dark( 120 ) : gray.light( 120 );
- }
- else
- color = Qt::darkGray;
- painter->save();
- painter->setBrush( Qt::NoBrush );
- painter->setPen( QPen( color, 0, Qt::DotLine ) );
- painter->drawEllipse( focusRect );
- painter->restore();
- }
- }
- /*!
- Draw the frame around the dial
- \param painter Painter
- \sa lineWidth(), frameShadow()
- */
- void QwtDial::drawFrame( QPainter *painter )
- {
- const int lw = lineWidth();
- const int off = ( lw + 1 ) % 2;
- QRect r = boundingRect();
- r.setRect( r.x() + lw / 2 - off, r.y() + lw / 2 - off,
- r.width() - lw + off + 1, r.height() - lw + off + 1 );
- r.setX( r.x() + 1 );
- r.setY( r.y() + 1 );
- r.setWidth( r.width() - 2 );
- r.setHeight( r.height() - 2 );
- if ( lw > 0 )
- {
- switch ( d_data->frameShadow )
- {
- case QwtDial::Raised:
- QwtPainter::drawRoundFrame( painter, r,
- lw, palette(), false );
- break;
- case QwtDial::Sunken:
- QwtPainter::drawRoundFrame( painter, r,
- lw, palette(), true );
- break;
- default: // Plain
- {
- painter->save();
- painter->setPen( QPen( Qt::black, lw ) );
- painter->setBrush( Qt::NoBrush );
- painter->drawEllipse( r );
- painter->restore();
- }
- }
- }
- }
- /*!
- \brief Draw the contents inside the frame
- QPalette::Window is the background color outside of the frame.
- QPalette::Base is the background color inside the frame.
- QPalette::WindowText is the background color inside the scale.
- \param painter Painter
- \sa boundingRect(), contentsRect(),
- scaleContentsRect(), QWidget::setPalette()
- */
- void QwtDial::drawContents( QPainter *painter ) const
- {
- if ( testAttribute( Qt::WA_NoSystemBackground ) ||
- palette().brush( QPalette::Base ) !=
- palette().brush( QPalette::Window ) )
- {
- const QRect br = boundingRect();
- painter->save();
- painter->setPen( Qt::NoPen );
- painter->setBrush( palette().brush( QPalette::Base ) );
- painter->drawEllipse( br );
- painter->restore();
- }
- const QRect insideScaleRect = scaleContentsRect();
- if ( palette().brush( QPalette::WindowText ) !=
- palette().brush( QPalette::Base ) )
- {
- painter->save();
- painter->setPen( Qt::NoPen );
- painter->setBrush( palette().brush( QPalette::WindowText ) );
- painter->drawEllipse( insideScaleRect.x() - 1, insideScaleRect.y() - 1,
- insideScaleRect.width(), insideScaleRect.height() );
- painter->restore();
- }
- const QPoint center = insideScaleRect.center();
- const int radius = insideScaleRect.width() / 2;
- painter->save();
- drawScaleContents( painter, center, radius );
- painter->restore();
- double direction = d_data->origin;
- if ( isValid() )
- {
- direction = d_data->minScaleArc;
- if ( maxValue() > minValue() && d_data->maxScaleArc > d_data->minScaleArc )
- {
- const double ratio =
- ( value() - minValue() ) / ( maxValue() - minValue() );
- direction += ratio * ( d_data->maxScaleArc - d_data->minScaleArc );
- }
- if ( d_data->direction == QwtDial::CounterClockwise )
- direction = d_data->maxScaleArc - ( direction - d_data->minScaleArc );
- direction += d_data->origin;
- if ( direction >= 360.0 )
- direction -= 360.0;
- else if ( direction < 0.0 )
- direction += 360.0;
- }
- double origin = d_data->origin;
- if ( mode() == RotateScale )
- {
- origin -= direction - d_data->origin;
- direction = d_data->origin;
- }
- painter->save();
- drawScale( painter, center, radius, origin,
- d_data->minScaleArc, d_data->maxScaleArc );
- painter->restore();
- if ( isValid() )
- {
- QPalette::ColorGroup cg;
- if ( isEnabled() )
- cg = hasFocus() ? QPalette::Active : QPalette::Inactive;
- else
- cg = QPalette::Disabled;
- painter->save();
- drawNeedle( painter, center, radius, direction, cg );
- painter->restore();
- }
- }
- /*!
- Draw the needle
- \param painter Painter
- \param center Center of the dial
- \param radius Length for the needle
- \param direction Direction of the needle in degrees, counter clockwise
- \param cg ColorGroup
- */
- void QwtDial::drawNeedle( QPainter *painter, const QPoint ¢er,
- int radius, double direction, QPalette::ColorGroup cg ) const
- {
- if ( d_data->needle )
- {
- direction = 360.0 - direction; // counter clockwise
- d_data->needle->draw( painter, center, radius, direction, cg );
- }
- }
- /*!
- Draw the scale
- \param painter Painter
- \param center Center of the dial
- \param radius Radius of the scale
- \param origin Origin of the scale
- \param minArc Minimum of the arc
- \param maxArc Minimum of the arc
- \sa QwtAbstractScaleDraw::setAngleRange()
- */
- void QwtDial::drawScale( QPainter *painter, const QPoint ¢er,
- int radius, double origin, double minArc, double maxArc ) const
- {
- if ( d_data->scaleDraw == NULL )
- return;
- origin -= 270.0; // hardcoded origin of QwtScaleDraw
- double angle = maxArc - minArc;
- if ( angle > 360.0 )
- angle = ::fmod( angle, 360.0 );
- minArc += origin;
- if ( minArc < -360.0 )
- minArc = ::fmod( minArc, 360.0 );
- maxArc = minArc + angle;
- if ( maxArc > 360.0 )
- {
- // QwtAbstractScaleDraw::setAngleRange accepts only values
- // in the range [-360.0..360.0]
- minArc -= 360.0;
- maxArc -= 360.0;
- }
- if ( d_data->direction == QwtDial::CounterClockwise )
- qSwap( minArc, maxArc );
- painter->setFont( font() );
- d_data->scaleDraw->setAngleRange( minArc, maxArc );
- d_data->scaleDraw->setRadius( radius );
- d_data->scaleDraw->moveCenter( center );
- QPalette pal = palette();
- const QColor textColor = pal.color( QPalette::Text );
- pal.setColor( QPalette::WindowText, textColor ); //ticks, backbone
- painter->setPen( QPen( textColor, d_data->scaleDraw->penWidth() ) );
- d_data->scaleDraw->draw( painter, pal );
- }
- void QwtDial::drawScaleContents( QPainter *,
- const QPoint &, int ) const
- {
- // empty default implementation
- }
- /*!
- Set a needle for the dial
- Qwt is missing a set of good looking needles.
- Contributions are very welcome.
- \param needle Needle
- \warning The needle will be deleted, when a different needle is
- set or in ~QwtDial()
- */
- void QwtDial::setNeedle( QwtDialNeedle *needle )
- {
- if ( needle != d_data->needle )
- {
- if ( d_data->needle )
- delete d_data->needle;
- d_data->needle = needle;
- update();
- }
- }
- /*!
- \return needle
- \sa setNeedle()
- */
- const QwtDialNeedle *QwtDial::needle() const
- {
- return d_data->needle;
- }
- /*!
- \return needle
- \sa setNeedle()
- */
- QwtDialNeedle *QwtDial::needle()
- {
- return d_data->needle;
- }
- //! QwtDoubleRange update hook
- void QwtDial::rangeChange()
- {
- updateScale();
- }
- /*!
- Update the scale with the current attributes
- \sa setScale()
- */
- void QwtDial::updateScale()
- {
- if ( d_data->scaleDraw )
- {
- QwtLinearScaleEngine scaleEngine;
- const QwtScaleDiv scaleDiv = scaleEngine.divideScale(
- minValue(), maxValue(),
- d_data->maxMajIntv, d_data->maxMinIntv, d_data->scaleStep );
- d_data->scaleDraw->setTransformation( scaleEngine.transformation() );
- d_data->scaleDraw->setScaleDiv( scaleDiv );
- }
- }
- //! Return the scale draw
- QwtDialScaleDraw *QwtDial::scaleDraw()
- {
- return d_data->scaleDraw;
- }
- //! Return the scale draw
- const QwtDialScaleDraw *QwtDial::scaleDraw() const
- {
- return d_data->scaleDraw;
- }
- /*!
- Set an individual scale draw
- \param scaleDraw Scale draw
- \warning The previous scale draw is deleted
- */
- void QwtDial::setScaleDraw( QwtDialScaleDraw *scaleDraw )
- {
- if ( scaleDraw != d_data->scaleDraw )
- {
- if ( d_data->scaleDraw )
- delete d_data->scaleDraw;
- d_data->scaleDraw = scaleDraw;
- updateScale();
- update();
- }
- }
- /*!
- Change the intervals of the scale
- \sa QwtAbstractScaleDraw::setScale()
- */
- void QwtDial::setScale( int maxMajIntv, int maxMinIntv, double step )
- {
- d_data->maxMajIntv = maxMajIntv;
- d_data->maxMinIntv = maxMinIntv;
- d_data->scaleStep = step;
- updateScale();
- }
- /*!
- A wrapper method for accessing the scale draw.
- - options == 0\n
- No visible scale: setScaleDraw(NULL)
- - options & ScaleBackbone\n
- En/disable the backbone of the scale.
- - options & ScaleTicks\n
- En/disable the ticks of the scale.
- - options & ScaleLabel\n
- En/disable scale labels
- \sa QwtAbstractScaleDraw::enableComponent()
- */
- void QwtDial::setScaleOptions( int options )
- {
- if ( options == 0 )
- setScaleDraw( NULL );
- QwtDialScaleDraw *sd = d_data->scaleDraw;
- if ( sd == NULL )
- return;
- sd->enableComponent( QwtAbstractScaleDraw::Backbone,
- options & ScaleBackbone );
- sd->enableComponent( QwtAbstractScaleDraw::Ticks,
- options & ScaleTicks );
- sd->enableComponent( QwtAbstractScaleDraw::Labels,
- options & ScaleLabel );
- }
- /*!
- Assign length and width of the ticks
- \param minLen Length of the minor ticks
- \param medLen Length of the medium ticks
- \param majLen Length of the major ticks
- \param penWidth Width of the pen for all ticks
- \sa QwtAbstractScaleDraw::setTickLength(), QwtDialScaleDraw::setPenWidth()
- */
- void QwtDial::setScaleTicks( int minLen, int medLen,
- int majLen, int penWidth )
- {
- QwtDialScaleDraw *sd = d_data->scaleDraw;
- if ( sd )
- {
- sd->setTickLength( QwtScaleDiv::MinorTick, minLen );
- sd->setTickLength( QwtScaleDiv::MediumTick, medLen );
- sd->setTickLength( QwtScaleDiv::MajorTick, majLen );
- sd->setPenWidth( penWidth );
- }
- }
- /*!
- Find the label for a value
- \param value Value
- \return label
- */
- QwtText QwtDial::scaleLabel( double value ) const
- {
- #if 1
- if ( value == -0 )
- value = 0;
- #endif
- return QString::number( value );
- }
- //! \return Lower limit of the scale arc
- double QwtDial::minScaleArc() const
- {
- return d_data->minScaleArc;
- }
- //! \return Upper limit of the scale arc
- double QwtDial::maxScaleArc() const
- {
- return d_data->maxScaleArc;
- }
- /*!
- \brief Change the origin
- The origin is the angle where scale and needle is relative to.
- \param origin New origin
- \sa origin()
- */
- void QwtDial::setOrigin( double origin )
- {
- d_data->origin = origin;
- update();
- }
- /*!
- The origin is the angle where scale and needle is relative to.
- \return Origin of the dial
- \sa setOrigin()
- */
- double QwtDial::origin() const
- {
- return d_data->origin;
- }
- /*!
- Change the arc of the scale
- \param minArc Lower limit
- \param maxArc Upper limit
- */
- void QwtDial::setScaleArc( double minArc, double maxArc )
- {
- if ( minArc != 360.0 && minArc != -360.0 )
- minArc = ::fmod( minArc, 360.0 );
- if ( maxArc != 360.0 && maxArc != -360.0 )
- maxArc = ::fmod( maxArc, 360.0 );
- d_data->minScaleArc = qMin( minArc, maxArc );
- d_data->maxScaleArc = qMax( minArc, maxArc );
- if ( d_data->maxScaleArc - d_data->minScaleArc > 360.0 )
- d_data->maxScaleArc = d_data->minScaleArc + 360.0;
- update();
- }
- //! QwtDoubleRange update hook
- void QwtDial::valueChange()
- {
- update();
- QwtAbstractSlider::valueChange();
- }
- /*!
- \return Size hint
- */
- QSize QwtDial::sizeHint() const
- {
- int sh = 0;
- if ( d_data->scaleDraw )
- sh = qCeil( d_data->scaleDraw->extent( font() ) );
- const int d = 6 * sh + 2 * lineWidth();
- return QSize( d, d );
- }
- /*!
- \brief Return a minimum size hint
- \warning The return value of QwtDial::minimumSizeHint() depends on the
- font and the scale.
- */
- QSize QwtDial::minimumSizeHint() const
- {
- int sh = 0;
- if ( d_data->scaleDraw )
- sh = qCeil( d_data->scaleDraw->extent( font() ) );
- const int d = 3 * sh + 2 * lineWidth();
- return QSize( d, d );
- }
- static double line2Radians( const QPoint &p1, const QPoint &p2 )
- {
- const QPoint p = p2 - p1;
- double angle;
- if ( p.x() == 0 )
- angle = ( p.y() <= 0 ) ? M_PI_2 : 3 * M_PI_2;
- else
- {
- angle = qAtan( double( -p.y() ) / double( p.x() ) );
- if ( p.x() < 0 )
- angle += M_PI;
- if ( angle < 0.0 )
- angle += 2 * M_PI;
- }
- return 360.0 - angle * 180.0 / M_PI;
- }
- /*!
- Find the value for a given position
- \param pos Position
- \return Value
- */
- double QwtDial::getValue( const QPoint &pos )
- {
- if ( d_data->maxScaleArc == d_data->minScaleArc || maxValue() == minValue() )
- return minValue();
- double dir = line2Radians( rect().center(), pos ) - d_data->origin;
- if ( dir < 0.0 )
- dir += 360.0;
- if ( mode() == RotateScale )
- dir = 360.0 - dir;
- // The position might be in the area that is outside the scale arc.
- // We need the range of the scale if it was a complete circle.
- const double completeCircle = 360.0 / ( d_data->maxScaleArc - d_data->minScaleArc )
- * ( maxValue() - minValue() );
- double posValue = minValue() + completeCircle * dir / 360.0;
- if ( scrollMode() == ScrMouse )
- {
- if ( d_data->previousDir >= 0.0 ) // valid direction
- {
- // We have to find out whether the mouse is moving
- // clock or counter clockwise
- bool clockWise = false;
- const double angle = dir - d_data->previousDir;
- if ( ( angle >= 0.0 && angle <= 180.0 ) || angle < -180.0 )
- clockWise = true;
- if ( clockWise )
- {
- if ( dir < d_data->previousDir && mouseOffset() > 0.0 )
- {
- // We passed 360 -> 0
- setMouseOffset( mouseOffset() - completeCircle );
- }
- if ( wrapping() )
- {
- if ( posValue - mouseOffset() > maxValue() )
- {
- // We passed maxValue and the value will be set
- // to minValue. We have to adjust the mouseOffset.
- setMouseOffset( posValue - minValue() );
- }
- }
- else
- {
- if ( posValue - mouseOffset() > maxValue() ||
- value() == maxValue() )
- {
- // We fix the value at maxValue by adjusting
- // the mouse offset.
- setMouseOffset( posValue - maxValue() );
- }
- }
- }
- else
- {
- if ( dir > d_data->previousDir && mouseOffset() < 0.0 )
- {
- // We passed 0 -> 360
- setMouseOffset( mouseOffset() + completeCircle );
- }
- if ( wrapping() )
- {
- if ( posValue - mouseOffset() < minValue() )
- {
- // We passed minValue and the value will be set
- // to maxValue. We have to adjust the mouseOffset.
- setMouseOffset( posValue - maxValue() );
- }
- }
- else
- {
- if ( posValue - mouseOffset() < minValue() ||
- value() == minValue() )
- {
- // We fix the value at minValue by adjusting
- // the mouse offset.
- setMouseOffset( posValue - minValue() );
- }
- }
- }
- }
- d_data->previousDir = dir;
- }
- return posValue;
- }
- /*!
- See QwtAbstractSlider::getScrollMode()
- \param pos point where the mouse was pressed
- \retval scrollMode The scrolling mode
- \retval direction direction: 1, 0, or -1.
- \sa QwtAbstractSlider::getScrollMode()
- */
- void QwtDial::getScrollMode( const QPoint &pos, int &scrollMode, int &direction )
- {
- direction = 0;
- scrollMode = ScrNone;
- const QRegion region( contentsRect(), QRegion::Ellipse );
- if ( region.contains( pos ) && pos != rect().center() )
- {
- scrollMode = ScrMouse;
- d_data->previousDir = -1.0;
- }
- }
- /*!
- Handles key events
- - Key_Down, KeyLeft\n
- Decrement by 1
- - Key_Prior\n
- Decrement by pageSize()
- - Key_Home\n
- Set the value to minValue()
- - Key_Up, KeyRight\n
- Increment by 1
- - Key_Next\n
- Increment by pageSize()
- - Key_End\n
- Set the value to maxValue()
- \param event Key event
- \sa isReadOnly()
- */
- void QwtDial::keyPressEvent( QKeyEvent *event )
- {
- if ( isReadOnly() )
- {
- event->ignore();
- return;
- }
- if ( !isValid() )
- return;
- double previous = prevValue();
- switch ( event->key() )
- {
- case Qt::Key_Down:
- case Qt::Key_Left:
- QwtDoubleRange::incValue( -1 );
- break;
- case Qt::Key_PageUp:
- QwtDoubleRange::incValue( -pageSize() );
- break;
- case Qt::Key_Home:
- setValue( minValue() );
- break;
- case Qt::Key_Up:
- case Qt::Key_Right:
- QwtDoubleRange::incValue( 1 );
- break;
- case Qt::Key_PageDown:
- QwtDoubleRange::incValue( pageSize() );
- break;
- case Qt::Key_End:
- setValue( maxValue() );
- break;
- default:;
- event->ignore();
- }
- if ( value() != previous )
- Q_EMIT sliderMoved( value() );
- }
- /*!
- \brief Update the mask of the dial
- In case of "hasVisibleBackground() == false", the backgound is
- transparent by a mask.
- \sa showBackground(), hasVisibleBackground()
- */
- void QwtDial::updateMask()
- {
- if ( d_data->visibleBackground )
- clearMask();
- else
- setMask( QRegion( boundingRect(), QRegion::Ellipse ) );
- }
|