10 #include "qwt_wheel.h"
12 #include "qwt_painter.h"
16 #include <qdrawutil.h>
19 #include <qstyleoption.h>
20 #include <qelapsedtimer.h>
23 class QwtWheel::PrivateData
46 , isScrolling( false )
49 , pendingValueChanged( false )
86 bool pendingValueChanged;
95 m_data =
new PrivateData;
97 setFocusPolicy( Qt::StrongFocus );
98 setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
99 setAttribute( Qt::WA_WState_OwnSizePolicy,
false );
122 m_data->tracking = enable;
131 return m_data->tracking;
144 m_data->updateInterval = qMax( interval, 50 );
153 return m_data->updateInterval;
167 m_data->isScrolling =
wheelRect().contains( event->pos() );
169 if ( m_data->isScrolling )
171 m_data->timer.start();
173 m_data->mouseValue =
valueAt( event->pos() );
174 m_data->mouseOffset = m_data->mouseValue - m_data->value;
175 m_data->pendingValueChanged =
false;
190 if ( !m_data->isScrolling )
193 double mouseValue =
valueAt( event->pos() );
195 if ( m_data->mass > 0.0 )
197 double ms = m_data->timer.restart();
202 ms = qMax( ms, 5.0 );
204 m_data->speed = ( mouseValue - m_data->mouseValue ) / ms;
207 m_data->mouseValue = mouseValue;
209 double value = boundedValue( mouseValue - m_data->mouseOffset );
210 if ( m_data->stepAlignment )
213 if (
value != m_data->value )
215 m_data->value =
value;
221 if ( m_data->tracking )
224 m_data->pendingValueChanged =
true;
241 if ( !m_data->isScrolling )
244 m_data->isScrolling =
false;
246 bool startFlying =
false;
248 if ( m_data->mass > 0.0 )
250 const qint64 ms = m_data->timer.elapsed();
251 if ( ( std::fabs( m_data->speed ) > 0.0 ) && ( ms < 50 ) )
257 m_data->flyingValue =
258 boundedValue( m_data->mouseValue - m_data->mouseOffset );
260 m_data->timerId = startTimer( m_data->updateInterval );
264 if ( m_data->pendingValueChanged )
268 m_data->pendingValueChanged =
false;
269 m_data->mouseOffset = 0.0;
285 if ( event->timerId() != m_data->timerId )
287 QWidget::timerEvent( event );
291 m_data->speed *= std::exp( -m_data->updateInterval * 0.001 / m_data->mass );
293 m_data->flyingValue += m_data->speed * m_data->updateInterval;
294 m_data->flyingValue = boundedValue( m_data->flyingValue );
296 double value = m_data->flyingValue;
297 if ( m_data->stepAlignment )
300 if ( std::fabs( m_data->speed ) < 0.001 * m_data->singleStep )
306 if (
value != m_data->value )
308 m_data->value =
value;
311 if ( m_data->tracking || m_data->timerId == 0 )
326 #if QT_VERSION < 0x050e00
327 const QPoint wheelPos =
event->pos();
328 const int wheelDelta =
event->delta();
330 const QPoint wheelPos =
event->position().toPoint();
332 const QPoint delta =
event->angleDelta();
333 const int wheelDelta = ( qAbs( delta.x() ) > qAbs( delta.y() ) )
334 ? delta.x() : delta.y();
343 if ( m_data->isScrolling )
348 double increment = 0.0;
350 if ( ( event->modifiers() & Qt::ControlModifier ) ||
351 ( event->modifiers() & Qt::ShiftModifier ) )
354 increment = m_data->singleStep * m_data->pageStepCount;
355 if ( wheelDelta < 0 )
356 increment = -increment;
360 const int numSteps = wheelDelta / 120;
361 increment = m_data->singleStep * numSteps;
364 if ( m_data->orientation == Qt::Vertical && m_data->inverted )
365 increment = -increment;
367 double value = boundedValue( m_data->value + increment );
369 if ( m_data->stepAlignment )
372 if (
value != m_data->value )
374 m_data->value =
value;
411 if ( m_data->isScrolling )
417 double value = m_data->value;
418 double increment = 0.0;
420 switch ( event->key() )
424 if ( m_data->orientation == Qt::Vertical && m_data->inverted )
425 increment = m_data->singleStep;
427 increment = -m_data->singleStep;
433 if ( m_data->orientation == Qt::Vertical && m_data->inverted )
434 increment = -m_data->singleStep;
436 increment = m_data->singleStep;
442 if ( m_data->orientation == Qt::Horizontal )
444 if ( m_data->inverted )
445 increment = m_data->singleStep;
447 increment = -m_data->singleStep;
453 if ( m_data->orientation == Qt::Horizontal )
455 if ( m_data->inverted )
456 increment = -m_data->singleStep;
458 increment = m_data->singleStep;
464 increment = m_data->pageStepCount * m_data->singleStep;
467 case Qt::Key_PageDown:
469 increment = -m_data->pageStepCount * m_data->singleStep;
474 value = m_data->minimum;
479 value = m_data->maximum;
488 if ( event->isAccepted() )
491 if ( increment != 0.0 )
493 value = boundedValue( m_data->value + increment );
495 if ( m_data->stepAlignment )
499 if (
value != m_data->value )
501 m_data->value =
value;
521 count = qBound( 6, count, 50 );
523 if ( count != m_data->tickCount )
525 m_data->tickCount = qBound( 6, count, 50 );
536 return m_data->tickCount;
553 const int d = qMin( width(), height() ) / 3;
565 return m_data->wheelBorderWidth;
578 m_data->borderWidth = qMax( width, 0 );
588 return m_data->borderWidth;
596 const int bw = m_data->borderWidth;
597 return contentsRect().adjusted( bw, bw, -bw, -bw );
618 m_data->totalAngle = angle;
628 return m_data->totalAngle;
644 if ( !testAttribute( Qt::WA_WState_OwnSizePolicy ) )
646 QSizePolicy sp = sizePolicy();
650 setAttribute( Qt::WA_WState_OwnSizePolicy,
false );
663 return m_data->orientation;
678 m_data->viewAngle = qBound( 10.0, angle, 175.0 );
688 return m_data->viewAngle;
702 if ( m_data->orientation == Qt::Vertical )
705 dx = rect.top() - pos.y();
710 dx = pos.x() - rect.left();
716 if ( m_data->inverted )
723 const double ang = dx * m_data->viewAngle / w;
727 const double val = ang * (
maximum() -
minimum() ) / m_data->totalAngle;
738 QPainter painter(
this );
739 painter.setClipRegion( event->region() );
743 style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter,
this);
745 qDrawShadePanel( &painter,
746 contentsRect(), palette(),
true, m_data->borderWidth );
762 QPainter* painter,
const QRectF& rect )
766 QPalette pal = palette();
769 QLinearGradient gradient( rect.topLeft(),
770 ( m_data->orientation == Qt::Horizontal ) ? rect.topRight() : rect.bottomLeft() );
771 gradient.setColorAt( 0.0, pal.color( QPalette::Button ) );
772 gradient.setColorAt( 0.2, pal.color( QPalette::Midlight ) );
773 gradient.setColorAt( 0.7, pal.color( QPalette::Mid ) );
774 gradient.setColorAt( 1.0, pal.color( QPalette::Dark ) );
776 painter->fillRect( rect, gradient );
780 const QPen lightPen( palette().color( QPalette::Light ),
781 m_data->wheelBorderWidth, Qt::SolidLine, Qt::FlatCap );
782 const QPen darkPen( pal.color( QPalette::Dark ),
783 m_data->wheelBorderWidth, Qt::SolidLine, Qt::FlatCap );
785 const double bw2 = 0.5 * m_data->wheelBorderWidth;
787 if ( m_data->orientation == Qt::Horizontal )
789 painter->setPen( lightPen );
790 painter->drawLine( QPointF( rect.left(), rect.top() + bw2 ),
791 QPointF( rect.right(), rect.top() + bw2 ) );
793 painter->setPen( darkPen );
794 painter->drawLine( QPointF( rect.left(), rect.bottom() - bw2 ),
795 QPointF( rect.right(), rect.bottom() - bw2 ) );
799 painter->setPen( lightPen );
800 painter->drawLine( QPointF( rect.left() + bw2, rect.top() ),
801 QPointF( rect.left() + bw2, rect.bottom() ) );
803 painter->setPen( darkPen );
804 painter->drawLine( QPointF( rect.right() - bw2, rect.top() ),
805 QPointF( rect.right() - bw2, rect.bottom() ) );
819 const double range = m_data->maximum - m_data->minimum;
821 if ( range == 0.0 || m_data->totalAngle == 0.0 )
826 const QPen lightPen( palette().color( QPalette::Light ),
827 0, Qt::SolidLine, Qt::FlatCap );
828 const QPen darkPen( palette().color( QPalette::Dark ),
829 0, Qt::SolidLine, Qt::FlatCap );
831 const double cnvFactor = qAbs( m_data->totalAngle / range );
832 const double halfIntv = 0.5 * m_data->viewAngle / cnvFactor;
833 const double loValue =
value() - halfIntv;
834 const double hiValue =
value() + halfIntv;
835 const double tickWidth = 360.0 / double( m_data->tickCount ) / cnvFactor;
836 const double sinArc = qFastSin( m_data->viewAngle * M_PI / 360.0 );
838 if ( m_data->orientation == Qt::Horizontal )
840 const double radius = rect.width() * 0.5;
842 double l1 = rect.top() + m_data->wheelBorderWidth;
843 double l2 = rect.bottom() - m_data->wheelBorderWidth - 1;
846 if ( m_data->wheelBorderWidth > 1 )
852 const double maxpos = rect.right() - 2;
853 const double minpos = rect.left() + 2;
856 for (
double tickValue = std::ceil( loValue / tickWidth ) * tickWidth;
857 tickValue < hiValue; tickValue += tickWidth )
859 const double angle = qwtRadians( tickValue -
value() );
860 const double s = qFastSin( angle * cnvFactor );
862 const double off = radius * ( sinArc + s ) / sinArc;
865 if ( m_data->inverted )
866 tickPos = rect.left() + off;
868 tickPos = rect.right() - off;
870 if ( ( tickPos <= maxpos ) && ( tickPos > minpos ) )
872 painter->setPen( darkPen );
873 painter->drawLine( QPointF( tickPos - 1, l1 ),
874 QPointF( tickPos - 1, l2 ) );
875 painter->setPen( lightPen );
876 painter->drawLine( QPointF( tickPos, l1 ),
877 QPointF( tickPos, l2 ) );
883 const double radius = rect.height() * 0.5;
885 double l1 = rect.left() + m_data->wheelBorderWidth;
886 double l2 = rect.right() - m_data->wheelBorderWidth - 1;
888 if ( m_data->wheelBorderWidth > 1 )
894 const double maxpos = rect.bottom() - 2;
895 const double minpos = rect.top() + 2;
897 for (
double tickValue = std::ceil( loValue / tickWidth ) * tickWidth;
898 tickValue < hiValue; tickValue += tickWidth )
900 const double angle = qwtRadians( tickValue -
value() );
901 const double s = qFastSin( angle * cnvFactor );
903 const double off = radius * ( sinArc + s ) / sinArc;
907 if ( m_data->inverted )
908 tickPos = rect.bottom() - off;
910 tickPos = rect.top() + off;
912 if ( ( tickPos <= maxpos ) && ( tickPos > minpos ) )
914 painter->setPen( darkPen );
915 painter->drawLine( QPointF( l1, tickPos - 1 ),
916 QPointF( l2, tickPos - 1 ) );
917 painter->setPen( lightPen );
918 painter->drawLine( QPointF( l1, tickPos ),
919 QPointF( l2, tickPos ) );
936 m_data->wheelWidth = width;
946 return m_data->wheelWidth;
955 return qwtExpandedToGlobalStrut( hint );
964 QSize sz( 3 * m_data->wheelWidth + 2 * m_data->borderWidth,
965 m_data->wheelWidth + 2 * m_data->borderWidth );
966 if ( m_data->orientation != Qt::Horizontal )
982 m_data->singleStep = qwtMaxF( stepSize, 0.0 );
991 return m_data->singleStep;
1006 if ( on != m_data->stepAlignment )
1008 m_data->stepAlignment = on;
1018 return m_data->stepAlignment;
1036 m_data->pageStepCount = qMax( 0, count );
1045 return m_data->pageStepCount;
1061 max = qwtMaxF( min, max );
1063 if ( m_data->minimum == min && m_data->maximum == max )
1066 m_data->minimum = min;
1067 m_data->maximum = max;
1069 if ( m_data->value < min || m_data->value > max )
1071 m_data->value = qBound( min, m_data->value, max );
1096 return m_data->minimum;
1116 return m_data->maximum;
1130 m_data->isScrolling =
false;
1132 value = qBound( m_data->minimum,
value, m_data->maximum );
1134 if ( m_data->value !=
value )
1136 m_data->value =
value;
1149 return m_data->value;
1165 if ( m_data->inverted != on )
1167 m_data->inverted = on;
1178 return m_data->inverted;
1192 m_data->wrapping = on;
1201 return m_data->wrapping;
1229 m_data->mass = qwtMinF( 100.0,
mass );
1232 if ( m_data->mass <= 0.0 )
1242 return m_data->mass;
1248 if ( m_data->timerId != 0 )
1250 killTimer( m_data->timerId );
1251 m_data->timerId = 0;
1252 m_data->speed = 0.0;
1256 double QwtWheel::boundedValue(
double value )
const
1258 const double range = m_data->maximum - m_data->minimum;
1260 if ( m_data->wrapping && range >= 0.0 )
1262 if ( value < m_data->
minimum )
1264 value += std::ceil( ( m_data->minimum -
value ) / range ) * range;
1266 else if (
value > m_data->maximum )
1268 value -= std::ceil( (
value - m_data->maximum ) / range ) * range;
1273 value = qBound( m_data->minimum,
value, m_data->maximum );
1279 double QwtWheel::alignedValue(
double value )
const
1281 const double stepSize = m_data->singleStep;
1283 if ( stepSize > 0.0 )
1285 value = m_data->minimum +
1286 qRound( (
value - m_data->minimum ) / stepSize ) * stepSize;
1288 if ( stepSize > 1e-12 )
1290 if ( qFuzzyCompare(
value + 1.0, 1.0 ) )
1295 else if ( qFuzzyCompare(
value, m_data->maximum ) )
1298 value = m_data->maximum;
1307 #include "moc_qwt_wheel.cpp"
static void drawFocusRect(QPainter *, const QWidget *)
Draw a focus rectangle on a widget using its style.
virtual void paintEvent(QPaintEvent *) override
Qt Paint Event.
virtual void wheelEvent(QWheelEvent *) override
Handle wheel events.
Qt::Orientation orientation() const
bool stepAlignment() const
virtual QSize sizeHint() const override
void setMass(double)
Set the slider's mass for flywheel effect.
virtual void drawWheelBackground(QPainter *, const QRectF &)
virtual QSize minimumSizeHint() const override
void setTracking(bool)
En/Disable tracking.
virtual void mouseReleaseEvent(QMouseEvent *) override
Mouse Release Event handler.
void setWheelBorderWidth(int)
Set the wheel border width of the wheel.
void setBorderWidth(int)
Set the border width.
void setRange(double min, double max)
Set the minimum and maximum values.
virtual ~QwtWheel()
Destructor.
int updateInterval() const
virtual void timerEvent(QTimerEvent *) override
Qt timer event.
void setUpdateInterval(int)
Specify the update interval when the wheel is flying.
void setStepAlignment(bool on)
En/Disable step alignment.
virtual void mouseMoveEvent(QMouseEvent *) override
Mouse Move Event handler.
void setSingleStep(double)
Set the step size of the counter.
void setValue(double)
Set a new value without adjusting to the step raster.
void wheelMoved(double value)
int pageStepCount() const
void setViewAngle(double)
Specify the visible portion of the wheel.
virtual void mousePressEvent(QMouseEvent *) override
Mouse press event handler.
QwtWheel(QWidget *parent=NULL)
Constructor.
int wheelBorderWidth() const
virtual double valueAt(const QPoint &) const
virtual void drawTicks(QPainter *, const QRectF &)
void setWheelWidth(int)
Set the width of the wheel.
void setOrientation(Qt::Orientation)
Set the wheel's orientation.
void valueChanged(double value)
Notify a change of value.
void setPageStepCount(int)
Set the page step count.
void setTickCount(int)
Adjust the number of grooves in the wheel's surface.
virtual void keyPressEvent(QKeyEvent *) override
void setTotalAngle(double)
Set the total angle which the wheel can be turned.
void setWrapping(bool)
En/Disable wrapping.
double totalAngle() const
double singleStep() const
void stopFlying()
Stop the flying movement of the wheel.
void setInverted(bool)
En/Disable inverted appearance.