1005 lines
23 KiB
C++
1005 lines
23 KiB
C++
|
/* -*- 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_slider.h"
|
||
|
#include "qwt_painter.h"
|
||
|
#include "qwt_scale_draw.h"
|
||
|
#include "qwt_scale_map.h"
|
||
|
#include <qevent.h>
|
||
|
#include <qdrawutil.h>
|
||
|
#include <qpainter.h>
|
||
|
#include <qalgorithms.h>
|
||
|
#include <qmath.h>
|
||
|
#include <qstyle.h>
|
||
|
#include <qstyleoption.h>
|
||
|
#include <qapplication.h>
|
||
|
|
||
|
static QSize qwtHandleSize( const QSize &size,
|
||
|
Qt::Orientation orientation, bool hasTrough )
|
||
|
{
|
||
|
QSize handleSize = size;
|
||
|
|
||
|
if ( handleSize.isEmpty() )
|
||
|
{
|
||
|
const int handleThickness = 16;
|
||
|
handleSize.setWidth( 2 * handleThickness );
|
||
|
handleSize.setHeight( handleThickness );
|
||
|
|
||
|
if ( !hasTrough )
|
||
|
handleSize.transpose();
|
||
|
|
||
|
if ( orientation == Qt::Vertical )
|
||
|
handleSize.transpose();
|
||
|
}
|
||
|
|
||
|
return handleSize;
|
||
|
}
|
||
|
|
||
|
static QwtScaleDraw::Alignment qwtScaleDrawAlignment(
|
||
|
Qt::Orientation orientation, QwtSlider::ScalePosition scalePos )
|
||
|
{
|
||
|
QwtScaleDraw::Alignment align;
|
||
|
|
||
|
if ( orientation == Qt::Vertical )
|
||
|
{
|
||
|
// NoScale lays out like Left
|
||
|
if ( scalePos == QwtSlider::LeadingScale )
|
||
|
align = QwtScaleDraw::RightScale;
|
||
|
else
|
||
|
align = QwtScaleDraw::LeftScale;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// NoScale lays out like Bottom
|
||
|
if ( scalePos == QwtSlider::TrailingScale )
|
||
|
align = QwtScaleDraw::TopScale;
|
||
|
else
|
||
|
align = QwtScaleDraw::BottomScale;
|
||
|
}
|
||
|
|
||
|
return align;
|
||
|
}
|
||
|
|
||
|
class QwtSlider::PrivateData
|
||
|
{
|
||
|
public:
|
||
|
PrivateData():
|
||
|
repeatTimerId( 0 ),
|
||
|
updateInterval( 150 ),
|
||
|
stepsIncrement( 0 ),
|
||
|
pendingValueChange( false ),
|
||
|
borderWidth( 2 ),
|
||
|
spacing( 4 ),
|
||
|
scalePosition( QwtSlider::TrailingScale ),
|
||
|
hasTrough( true ),
|
||
|
hasGroove( false ),
|
||
|
mouseOffset( 0 )
|
||
|
{
|
||
|
}
|
||
|
|
||
|
int repeatTimerId;
|
||
|
bool timerTick;
|
||
|
int updateInterval;
|
||
|
int stepsIncrement;
|
||
|
bool pendingValueChange;
|
||
|
|
||
|
QRect sliderRect;
|
||
|
|
||
|
QSize handleSize;
|
||
|
int borderWidth;
|
||
|
int spacing;
|
||
|
|
||
|
Qt::Orientation orientation;
|
||
|
QwtSlider::ScalePosition scalePosition;
|
||
|
|
||
|
bool hasTrough;
|
||
|
bool hasGroove;
|
||
|
|
||
|
int mouseOffset;
|
||
|
|
||
|
mutable QSize sizeHintCache;
|
||
|
};
|
||
|
/*!
|
||
|
Construct vertical slider in QwtSlider::Trough style
|
||
|
with a scale to the left.
|
||
|
|
||
|
The scale is initialized to [0.0, 100.0] and the value set to 0.0.
|
||
|
|
||
|
\param parent Parent widget
|
||
|
|
||
|
\sa setOrientation(), setScalePosition(), setBackgroundStyle()
|
||
|
*/
|
||
|
QwtSlider::QwtSlider( QWidget *parent ):
|
||
|
QwtAbstractSlider( parent )
|
||
|
{
|
||
|
initSlider( Qt::Vertical );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Construct a slider in QwtSlider::Trough style
|
||
|
|
||
|
When orientation is Qt::Vertical the scale will be aligned to
|
||
|
the left - otherwise at the the top of the slider.
|
||
|
|
||
|
The scale is initialized to [0.0, 100.0] and the value set to 0.0.
|
||
|
|
||
|
\param parent Parent widget
|
||
|
\param orientation Orientation of the slider.
|
||
|
*/
|
||
|
QwtSlider::QwtSlider( Qt::Orientation orientation, QWidget *parent ):
|
||
|
QwtAbstractSlider( parent )
|
||
|
{
|
||
|
initSlider( orientation );
|
||
|
}
|
||
|
|
||
|
//! Destructor
|
||
|
QwtSlider::~QwtSlider()
|
||
|
{
|
||
|
delete d_data;
|
||
|
}
|
||
|
|
||
|
void QwtSlider::initSlider( Qt::Orientation orientation )
|
||
|
{
|
||
|
if ( orientation == Qt::Vertical )
|
||
|
setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Expanding );
|
||
|
else
|
||
|
setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
|
||
|
|
||
|
setAttribute( Qt::WA_WState_OwnSizePolicy, false );
|
||
|
|
||
|
d_data = new QwtSlider::PrivateData;
|
||
|
|
||
|
d_data->orientation = orientation;
|
||
|
|
||
|
scaleDraw()->setAlignment(
|
||
|
qwtScaleDrawAlignment( orientation, d_data->scalePosition ) );
|
||
|
scaleDraw()->setLength( 100 );
|
||
|
|
||
|
setScale( 0.0, 100.0 );
|
||
|
setValue( 0.0 );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Set the orientation.
|
||
|
\param orientation Allowed values are Qt::Horizontal and Qt::Vertical.
|
||
|
|
||
|
\sa orientation(), scalePosition()
|
||
|
*/
|
||
|
void QwtSlider::setOrientation( Qt::Orientation orientation )
|
||
|
{
|
||
|
if ( orientation == d_data->orientation )
|
||
|
return;
|
||
|
|
||
|
d_data->orientation = orientation;
|
||
|
|
||
|
scaleDraw()->setAlignment(
|
||
|
qwtScaleDrawAlignment( orientation, d_data->scalePosition ) );
|
||
|
|
||
|
if ( !testAttribute( Qt::WA_WState_OwnSizePolicy ) )
|
||
|
{
|
||
|
QSizePolicy sp = sizePolicy();
|
||
|
sp.transpose();
|
||
|
setSizePolicy( sp );
|
||
|
|
||
|
setAttribute( Qt::WA_WState_OwnSizePolicy, false );
|
||
|
}
|
||
|
|
||
|
if ( testAttribute( Qt::WA_WState_Polished ) )
|
||
|
layoutSlider( true );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\return Orientation
|
||
|
\sa setOrientation()
|
||
|
*/
|
||
|
Qt::Orientation QwtSlider::orientation() const
|
||
|
{
|
||
|
return d_data->orientation;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Change the position of the scale
|
||
|
\param scalePosition Position of the scale.
|
||
|
|
||
|
\sa ScalePosition, scalePosition()
|
||
|
*/
|
||
|
void QwtSlider::setScalePosition( ScalePosition scalePosition )
|
||
|
{
|
||
|
if ( d_data->scalePosition == scalePosition )
|
||
|
return;
|
||
|
|
||
|
d_data->scalePosition = scalePosition;
|
||
|
scaleDraw()->setAlignment(
|
||
|
qwtScaleDrawAlignment( d_data->orientation, scalePosition ) );
|
||
|
|
||
|
if ( testAttribute( Qt::WA_WState_Polished ) )
|
||
|
layoutSlider( true );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\return Position of the scale
|
||
|
\sa setScalePosition()
|
||
|
*/
|
||
|
QwtSlider::ScalePosition QwtSlider::scalePosition() const
|
||
|
{
|
||
|
return d_data->scalePosition;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Change the slider's border width
|
||
|
|
||
|
The border width is used for drawing the slider handle and the
|
||
|
trough.
|
||
|
|
||
|
\param width Border width
|
||
|
\sa borderWidth()
|
||
|
*/
|
||
|
void QwtSlider::setBorderWidth( int width )
|
||
|
{
|
||
|
if ( width < 0 )
|
||
|
width = 0;
|
||
|
|
||
|
if ( width != d_data->borderWidth )
|
||
|
{
|
||
|
d_data->borderWidth = width;
|
||
|
|
||
|
if ( testAttribute( Qt::WA_WState_Polished ) )
|
||
|
layoutSlider( true );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\return the border width.
|
||
|
\sa setBorderWidth()
|
||
|
*/
|
||
|
int QwtSlider::borderWidth() const
|
||
|
{
|
||
|
return d_data->borderWidth;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Change the spacing between trough and scale
|
||
|
|
||
|
A spacing of 0 means, that the backbone of the scale is covered
|
||
|
by the trough.
|
||
|
|
||
|
The default setting is 4 pixels.
|
||
|
|
||
|
\param spacing Number of pixels
|
||
|
\sa spacing();
|
||
|
*/
|
||
|
void QwtSlider::setSpacing( int spacing )
|
||
|
{
|
||
|
if ( spacing <= 0 )
|
||
|
spacing = 0;
|
||
|
|
||
|
if ( spacing != d_data->spacing )
|
||
|
{
|
||
|
d_data->spacing = spacing;
|
||
|
|
||
|
if ( testAttribute( Qt::WA_WState_Polished ) )
|
||
|
layoutSlider( true );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\return Number of pixels between slider and scale
|
||
|
\sa setSpacing()
|
||
|
*/
|
||
|
int QwtSlider::spacing() const
|
||
|
{
|
||
|
return d_data->spacing;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Set the slider's handle size
|
||
|
|
||
|
When the size is empty the slider handle will be painted with a
|
||
|
default size depending on its orientation() and backgroundStyle().
|
||
|
|
||
|
\param size New size
|
||
|
|
||
|
\sa handleSize()
|
||
|
*/
|
||
|
void QwtSlider::setHandleSize( const QSize &size )
|
||
|
{
|
||
|
if ( size != d_data->handleSize )
|
||
|
{
|
||
|
d_data->handleSize = size;
|
||
|
|
||
|
if ( testAttribute( Qt::WA_WState_Polished ) )
|
||
|
layoutSlider( true );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\return Size of the handle.
|
||
|
\sa setHandleSize()
|
||
|
*/
|
||
|
QSize QwtSlider::handleSize() const
|
||
|
{
|
||
|
return d_data->handleSize;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Set a scale draw
|
||
|
|
||
|
For changing the labels of the scales, it
|
||
|
is necessary to derive from QwtScaleDraw and
|
||
|
overload QwtScaleDraw::label().
|
||
|
|
||
|
\param scaleDraw ScaleDraw object, that has to be created with
|
||
|
new and will be deleted in ~QwtSlider() or the next
|
||
|
call of setScaleDraw().
|
||
|
|
||
|
\sa scaleDraw()
|
||
|
*/
|
||
|
void QwtSlider::setScaleDraw( QwtScaleDraw *scaleDraw )
|
||
|
{
|
||
|
const QwtScaleDraw *previousScaleDraw = this->scaleDraw();
|
||
|
if ( scaleDraw == NULL || scaleDraw == previousScaleDraw )
|
||
|
return;
|
||
|
|
||
|
if ( previousScaleDraw )
|
||
|
scaleDraw->setAlignment( previousScaleDraw->alignment() );
|
||
|
|
||
|
setAbstractScaleDraw( scaleDraw );
|
||
|
|
||
|
if ( testAttribute( Qt::WA_WState_Polished ) )
|
||
|
layoutSlider( true );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\return the scale draw of the slider
|
||
|
\sa setScaleDraw()
|
||
|
*/
|
||
|
const QwtScaleDraw *QwtSlider::scaleDraw() const
|
||
|
{
|
||
|
return static_cast<const QwtScaleDraw *>( abstractScaleDraw() );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\return the scale draw of the slider
|
||
|
\sa setScaleDraw()
|
||
|
*/
|
||
|
QwtScaleDraw *QwtSlider::scaleDraw()
|
||
|
{
|
||
|
return static_cast<QwtScaleDraw *>( abstractScaleDraw() );
|
||
|
}
|
||
|
|
||
|
//! Notify changed scale
|
||
|
void QwtSlider::scaleChange()
|
||
|
{
|
||
|
QwtAbstractSlider::scaleChange();
|
||
|
|
||
|
if ( testAttribute( Qt::WA_WState_Polished ) )
|
||
|
layoutSlider( true );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Specify the update interval for automatic scrolling
|
||
|
|
||
|
The minimal accepted value is 50 ms.
|
||
|
|
||
|
\param interval Update interval in milliseconds
|
||
|
|
||
|
\sa setUpdateInterval()
|
||
|
*/
|
||
|
void QwtSlider::setUpdateInterval( int interval )
|
||
|
{
|
||
|
d_data->updateInterval = qMax( interval, 50 );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\return Update interval in milliseconds for automatic scrolling
|
||
|
\sa setUpdateInterval()
|
||
|
*/
|
||
|
int QwtSlider::updateInterval() const
|
||
|
{
|
||
|
return d_data->updateInterval;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Draw the slider into the specified rectangle.
|
||
|
|
||
|
\param painter Painter
|
||
|
\param sliderRect Bounding rectangle of the slider
|
||
|
*/
|
||
|
void QwtSlider::drawSlider(
|
||
|
QPainter *painter, const QRect &sliderRect ) const
|
||
|
{
|
||
|
QRect innerRect( sliderRect );
|
||
|
|
||
|
if ( d_data->hasTrough )
|
||
|
{
|
||
|
const int bw = d_data->borderWidth;
|
||
|
innerRect = sliderRect.adjusted( bw, bw, -bw, -bw );
|
||
|
|
||
|
painter->fillRect( innerRect, palette().brush( QPalette::Mid ) );
|
||
|
qDrawShadePanel( painter, sliderRect, palette(), true, bw, NULL );
|
||
|
}
|
||
|
|
||
|
const QSize handleSize = qwtHandleSize( d_data->handleSize,
|
||
|
d_data->orientation, d_data->hasTrough );
|
||
|
|
||
|
if ( d_data->hasGroove )
|
||
|
{
|
||
|
const int slotExtent = 4;
|
||
|
const int slotMargin = 4;
|
||
|
|
||
|
QRect slotRect;
|
||
|
if ( orientation() == Qt::Horizontal )
|
||
|
{
|
||
|
int slotOffset = qMax( 1, handleSize.width() / 2 - slotMargin );
|
||
|
int slotHeight = slotExtent + ( innerRect.height() % 2 );
|
||
|
|
||
|
slotRect.setWidth( innerRect.width() - 2 * slotOffset );
|
||
|
slotRect.setHeight( slotHeight );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int slotOffset = qMax( 1, handleSize.height() / 2 - slotMargin );
|
||
|
int slotWidth = slotExtent + ( innerRect.width() % 2 );
|
||
|
|
||
|
slotRect.setWidth( slotWidth );
|
||
|
slotRect.setHeight( innerRect.height() - 2 * slotOffset );
|
||
|
|
||
|
}
|
||
|
|
||
|
slotRect.moveCenter( innerRect.center() );
|
||
|
|
||
|
QBrush brush = palette().brush( QPalette::Dark );
|
||
|
qDrawShadePanel( painter, slotRect, palette(), true, 1 , &brush );
|
||
|
}
|
||
|
|
||
|
if ( isValid() )
|
||
|
drawHandle( painter, handleRect(), transform( value() ) );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Draw the thumb at a position
|
||
|
|
||
|
\param painter Painter
|
||
|
\param handleRect Bounding rectangle of the handle
|
||
|
\param pos Position of the handle marker in widget coordinates
|
||
|
*/
|
||
|
void QwtSlider::drawHandle( QPainter *painter,
|
||
|
const QRect &handleRect, int pos ) const
|
||
|
{
|
||
|
const int bw = d_data->borderWidth;
|
||
|
|
||
|
qDrawShadePanel( painter,
|
||
|
handleRect, palette(), false, bw,
|
||
|
&palette().brush( QPalette::Button ) );
|
||
|
|
||
|
pos++; // shade line points one pixel below
|
||
|
if ( orientation() == Qt::Horizontal )
|
||
|
{
|
||
|
qDrawShadeLine( painter, pos, handleRect.top() + bw,
|
||
|
pos, handleRect.bottom() - bw, palette(), true, 1 );
|
||
|
}
|
||
|
else // Vertical
|
||
|
{
|
||
|
qDrawShadeLine( painter, handleRect.left() + bw, pos,
|
||
|
handleRect.right() - bw, pos, palette(), true, 1 );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Determine what to do when the user presses a mouse button.
|
||
|
|
||
|
\param pos Mouse position
|
||
|
|
||
|
\retval True, when handleRect() contains pos
|
||
|
\sa scrolledTo()
|
||
|
*/
|
||
|
bool QwtSlider::isScrollPosition( const QPoint &pos ) const
|
||
|
{
|
||
|
if ( handleRect().contains( pos ) )
|
||
|
{
|
||
|
const double v = ( orientation() == Qt::Horizontal )
|
||
|
? pos.x() : pos.y();
|
||
|
|
||
|
d_data->mouseOffset = v - transform( value() );
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Determine the value for a new position of the
|
||
|
slider handle.
|
||
|
|
||
|
\param pos Mouse position
|
||
|
|
||
|
\return Value for the mouse position
|
||
|
\sa isScrollPosition()
|
||
|
*/
|
||
|
double QwtSlider::scrolledTo( const QPoint &pos ) const
|
||
|
{
|
||
|
int p = ( orientation() == Qt::Horizontal )
|
||
|
? pos.x() : pos.y();
|
||
|
|
||
|
p -= d_data->mouseOffset;
|
||
|
|
||
|
int min = transform( lowerBound() );
|
||
|
int max = transform( upperBound() );
|
||
|
if ( min > max )
|
||
|
qSwap( min, max );
|
||
|
|
||
|
p = qBound( min, p, max );
|
||
|
|
||
|
return scaleMap().invTransform( p );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Mouse press event handler
|
||
|
\param event Mouse event
|
||
|
*/
|
||
|
void QwtSlider::mousePressEvent( QMouseEvent *event )
|
||
|
{
|
||
|
if ( isReadOnly() )
|
||
|
{
|
||
|
event->ignore();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const QPoint pos = event->pos();
|
||
|
|
||
|
if ( isValid() && d_data->sliderRect.contains( pos ) )
|
||
|
{
|
||
|
if ( !handleRect().contains( pos ) )
|
||
|
{
|
||
|
const int markerPos = transform( value() );
|
||
|
|
||
|
d_data->stepsIncrement = pageSteps();
|
||
|
|
||
|
if ( d_data->orientation == Qt::Horizontal )
|
||
|
{
|
||
|
if ( pos.x() < markerPos )
|
||
|
d_data->stepsIncrement = -d_data->stepsIncrement;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( pos.y() < markerPos )
|
||
|
d_data->stepsIncrement = -d_data->stepsIncrement;
|
||
|
}
|
||
|
|
||
|
if ( isInverted() )
|
||
|
d_data->stepsIncrement = -d_data->stepsIncrement;
|
||
|
|
||
|
const double v = value();
|
||
|
incrementValue( d_data->stepsIncrement );
|
||
|
|
||
|
if ( v != value() )
|
||
|
{
|
||
|
if ( isTracking() )
|
||
|
Q_EMIT valueChanged( value() );
|
||
|
else
|
||
|
d_data->pendingValueChange = true;
|
||
|
|
||
|
Q_EMIT sliderMoved( value() );
|
||
|
}
|
||
|
|
||
|
d_data->timerTick = false;
|
||
|
d_data->repeatTimerId = startTimer( qMax( 250, 2 * updateInterval() ) );
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
QwtAbstractSlider::mousePressEvent( event );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Mouse release event handler
|
||
|
\param event Mouse event
|
||
|
*/
|
||
|
void QwtSlider::mouseReleaseEvent( QMouseEvent *event )
|
||
|
{
|
||
|
if ( d_data->repeatTimerId > 0 )
|
||
|
{
|
||
|
killTimer( d_data->repeatTimerId );
|
||
|
d_data->repeatTimerId = 0;
|
||
|
d_data->timerTick = false;
|
||
|
d_data->stepsIncrement = 0;
|
||
|
}
|
||
|
|
||
|
if ( d_data->pendingValueChange )
|
||
|
{
|
||
|
d_data->pendingValueChange = false;
|
||
|
Q_EMIT valueChanged( value() );
|
||
|
}
|
||
|
|
||
|
QwtAbstractSlider::mouseReleaseEvent( event );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Timer event handler
|
||
|
|
||
|
Handles the timer, when the mouse stays pressed
|
||
|
inside the sliderRect().
|
||
|
|
||
|
\param event Mouse event
|
||
|
*/
|
||
|
void QwtSlider::timerEvent( QTimerEvent *event )
|
||
|
{
|
||
|
if ( event->timerId() != d_data->repeatTimerId )
|
||
|
{
|
||
|
QwtAbstractSlider::timerEvent( event );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( !isValid() )
|
||
|
{
|
||
|
killTimer( d_data->repeatTimerId );
|
||
|
d_data->repeatTimerId = 0;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const double v = value();
|
||
|
incrementValue( d_data->stepsIncrement );
|
||
|
|
||
|
if ( v != value() )
|
||
|
{
|
||
|
if ( isTracking() )
|
||
|
Q_EMIT valueChanged( value() );
|
||
|
else
|
||
|
d_data->pendingValueChange = true;
|
||
|
|
||
|
Q_EMIT sliderMoved( value() );
|
||
|
}
|
||
|
|
||
|
if ( !d_data->timerTick )
|
||
|
{
|
||
|
// restart the timer with a shorter interval
|
||
|
killTimer( d_data->repeatTimerId );
|
||
|
d_data->repeatTimerId = startTimer( updateInterval() );
|
||
|
|
||
|
d_data->timerTick = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Qt paint event handler
|
||
|
\param event Paint event
|
||
|
*/
|
||
|
void QwtSlider::paintEvent( QPaintEvent *event )
|
||
|
{
|
||
|
QPainter painter( this );
|
||
|
painter.setClipRegion( event->region() );
|
||
|
|
||
|
QStyleOption opt;
|
||
|
opt.init(this);
|
||
|
style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
|
||
|
|
||
|
if ( d_data->scalePosition != QwtSlider::NoScale )
|
||
|
{
|
||
|
if ( !d_data->sliderRect.contains( event->rect() ) )
|
||
|
scaleDraw()->draw( &painter, palette() );
|
||
|
}
|
||
|
|
||
|
drawSlider( &painter, d_data->sliderRect );
|
||
|
|
||
|
if ( hasFocus() )
|
||
|
QwtPainter::drawFocusRect( &painter, this, d_data->sliderRect );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Qt resize event handler
|
||
|
\param event Resize event
|
||
|
*/
|
||
|
void QwtSlider::resizeEvent( QResizeEvent *event )
|
||
|
{
|
||
|
Q_UNUSED( event );
|
||
|
|
||
|
layoutSlider( false );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Handles QEvent::StyleChange and QEvent::FontChange events
|
||
|
\param event Change event
|
||
|
*/
|
||
|
void QwtSlider::changeEvent( QEvent *event )
|
||
|
{
|
||
|
if ( event->type() == QEvent::StyleChange ||
|
||
|
event->type() == QEvent::FontChange )
|
||
|
{
|
||
|
if ( testAttribute( Qt::WA_WState_Polished ) )
|
||
|
layoutSlider( true );
|
||
|
}
|
||
|
|
||
|
QwtAbstractSlider::changeEvent( event );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Recalculate the slider's geometry and layout based on
|
||
|
the current geometry and fonts.
|
||
|
|
||
|
\param update_geometry notify the layout system and call update
|
||
|
to redraw the scale
|
||
|
*/
|
||
|
void QwtSlider::layoutSlider( bool update_geometry )
|
||
|
{
|
||
|
int bw = 0;
|
||
|
if ( d_data->hasTrough )
|
||
|
bw = d_data->borderWidth;
|
||
|
|
||
|
const QSize handleSize = qwtHandleSize( d_data->handleSize,
|
||
|
d_data->orientation, d_data->hasTrough );
|
||
|
|
||
|
QRect sliderRect = contentsRect();
|
||
|
|
||
|
/*
|
||
|
The marker line of the handle needs to be aligned to
|
||
|
the scale. But the marker is in the center
|
||
|
and we need space enough to display the rest of the handle.
|
||
|
|
||
|
But the scale itself usually needs margins for displaying
|
||
|
the tick labels, that also might needs space beyond the
|
||
|
backbone.
|
||
|
|
||
|
Now it depends on what needs more margins. If it is the
|
||
|
slider the scale gets shrunk, otherwise the slider.
|
||
|
*/
|
||
|
|
||
|
int scaleMargin = 0;
|
||
|
if ( d_data->scalePosition != QwtSlider::NoScale )
|
||
|
{
|
||
|
int d1, d2;
|
||
|
scaleDraw()->getBorderDistHint( font(), d1, d2 );
|
||
|
|
||
|
scaleMargin = qMax( d1, d2 ) - bw;
|
||
|
}
|
||
|
|
||
|
int scaleX, scaleY, scaleLength;
|
||
|
|
||
|
if ( d_data->orientation == Qt::Horizontal )
|
||
|
{
|
||
|
const int handleMargin = handleSize.width() / 2 - 1;
|
||
|
if ( scaleMargin > handleMargin )
|
||
|
{
|
||
|
int off = scaleMargin - handleMargin;
|
||
|
sliderRect.adjust( off, 0, -off, 0 );
|
||
|
}
|
||
|
|
||
|
scaleX = sliderRect.left() + bw + handleSize.width() / 2 - 1;
|
||
|
scaleLength = sliderRect.width() - handleSize.width();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int handleMargin = handleSize.height() / 2 - 1;
|
||
|
if ( scaleMargin > handleMargin )
|
||
|
{
|
||
|
int off = scaleMargin - handleMargin;
|
||
|
sliderRect.adjust( 0, off, 0, -off );
|
||
|
}
|
||
|
|
||
|
scaleY = sliderRect.top() + bw + handleSize.height() / 2 - 1;
|
||
|
scaleLength = sliderRect.height() - handleSize.height();
|
||
|
}
|
||
|
|
||
|
scaleLength -= 2 * bw;
|
||
|
|
||
|
// now align slider and scale according to the ScalePosition
|
||
|
|
||
|
if ( d_data->orientation == Qt::Horizontal )
|
||
|
{
|
||
|
const int h = handleSize.height() + 2 * bw;
|
||
|
|
||
|
if ( d_data->scalePosition == QwtSlider::TrailingScale )
|
||
|
{
|
||
|
sliderRect.setTop( sliderRect.bottom() + 1 - h );
|
||
|
scaleY = sliderRect.top() - d_data->spacing;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sliderRect.setHeight( h );
|
||
|
scaleY = sliderRect.bottom() + 1 + d_data->spacing;
|
||
|
}
|
||
|
}
|
||
|
else // Qt::Vertical
|
||
|
{
|
||
|
const int w = handleSize.width() + 2 * bw;
|
||
|
|
||
|
if ( d_data->scalePosition == QwtSlider::LeadingScale )
|
||
|
{
|
||
|
sliderRect.setWidth( w );
|
||
|
scaleX = sliderRect.right() + 1 + d_data->spacing;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sliderRect.setLeft( sliderRect.right() + 1 - w );
|
||
|
scaleX = sliderRect.left() - d_data->spacing;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
d_data->sliderRect = sliderRect;
|
||
|
|
||
|
scaleDraw()->move( scaleX, scaleY );
|
||
|
scaleDraw()->setLength( scaleLength );
|
||
|
|
||
|
if ( update_geometry )
|
||
|
{
|
||
|
d_data->sizeHintCache = QSize(); // invalidate
|
||
|
updateGeometry();
|
||
|
update();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
En/Disable the trough
|
||
|
|
||
|
The slider can be cutomized by showing a trough for the
|
||
|
handle.
|
||
|
|
||
|
\param on When true, the groove is visible
|
||
|
\sa hasTrough(), setGroove()
|
||
|
*/
|
||
|
void QwtSlider::setTrough( bool on )
|
||
|
{
|
||
|
if ( d_data->hasTrough != on )
|
||
|
{
|
||
|
d_data->hasTrough = on;
|
||
|
|
||
|
if ( testAttribute( Qt::WA_WState_Polished ) )
|
||
|
layoutSlider( true );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\return True, when the trough is visisble
|
||
|
\sa setTrough(), hasGroove()
|
||
|
*/
|
||
|
bool QwtSlider::hasTrough() const
|
||
|
{
|
||
|
return d_data->hasTrough;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
En/Disable the groove
|
||
|
|
||
|
The slider can be cutomized by showing a groove for the
|
||
|
handle.
|
||
|
|
||
|
\param on When true, the groove is visible
|
||
|
\sa hasGroove(), setThrough()
|
||
|
*/
|
||
|
void QwtSlider::setGroove( bool on )
|
||
|
{
|
||
|
if ( d_data->hasGroove != on )
|
||
|
{
|
||
|
d_data->hasGroove = on;
|
||
|
|
||
|
if ( testAttribute( Qt::WA_WState_Polished ) )
|
||
|
layoutSlider( true );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\return True, when the groove is visisble
|
||
|
\sa setGroove(), hasTrough()
|
||
|
*/
|
||
|
bool QwtSlider::hasGroove() const
|
||
|
{
|
||
|
return d_data->hasGroove;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\return minimumSizeHint()
|
||
|
*/
|
||
|
QSize QwtSlider::sizeHint() const
|
||
|
{
|
||
|
const QSize hint = minimumSizeHint();
|
||
|
return hint.expandedTo( QApplication::globalStrut() );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\return Minimum size hint
|
||
|
\sa sizeHint()
|
||
|
*/
|
||
|
QSize QwtSlider::minimumSizeHint() const
|
||
|
{
|
||
|
if ( !d_data->sizeHintCache.isEmpty() )
|
||
|
return d_data->sizeHintCache;
|
||
|
|
||
|
const QSize handleSize = qwtHandleSize( d_data->handleSize,
|
||
|
d_data->orientation, d_data->hasTrough );
|
||
|
|
||
|
int bw = 0;
|
||
|
if ( d_data->hasTrough )
|
||
|
bw = d_data->borderWidth;
|
||
|
|
||
|
int sliderLength = 0;
|
||
|
int scaleExtent = 0;
|
||
|
|
||
|
if ( d_data->scalePosition != QwtSlider::NoScale )
|
||
|
{
|
||
|
int d1, d2;
|
||
|
scaleDraw()->getBorderDistHint( font(), d1, d2 );
|
||
|
|
||
|
const int scaleBorderDist = 2 * ( qMax( d1, d2 ) - bw );
|
||
|
|
||
|
int handleBorderDist;
|
||
|
if ( d_data->orientation == Qt::Horizontal )
|
||
|
handleBorderDist = handleSize.width();
|
||
|
else
|
||
|
handleBorderDist = handleSize.height();
|
||
|
|
||
|
sliderLength = scaleDraw()->minLength( font() );
|
||
|
if ( handleBorderDist > scaleBorderDist )
|
||
|
{
|
||
|
// We need additional space for the overlapping handle
|
||
|
sliderLength += handleBorderDist - scaleBorderDist;
|
||
|
}
|
||
|
|
||
|
scaleExtent += d_data->spacing;
|
||
|
scaleExtent += qCeil( scaleDraw()->extent( font() ) );
|
||
|
}
|
||
|
|
||
|
sliderLength = qMax( sliderLength, 84 ); // from QSlider
|
||
|
|
||
|
int w = 0;
|
||
|
int h = 0;
|
||
|
|
||
|
if ( d_data->orientation == Qt::Horizontal )
|
||
|
{
|
||
|
w = sliderLength;
|
||
|
h = handleSize.height() + 2 * bw + scaleExtent;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
w = handleSize.width() + 2 * bw + scaleExtent;
|
||
|
h = sliderLength;
|
||
|
}
|
||
|
|
||
|
// finally add margins
|
||
|
int left, right, top, bottom;
|
||
|
getContentsMargins( &left, &top, &right, &bottom );
|
||
|
|
||
|
w += left + right;
|
||
|
h += top + bottom;
|
||
|
|
||
|
d_data->sizeHintCache = QSize( w, h );
|
||
|
return d_data->sizeHintCache;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\return Bounding rectangle of the slider handle
|
||
|
*/
|
||
|
QRect QwtSlider::handleRect() const
|
||
|
{
|
||
|
if ( !isValid() )
|
||
|
return QRect();
|
||
|
|
||
|
const int markerPos = transform( value() );
|
||
|
|
||
|
QPoint center = d_data->sliderRect.center();
|
||
|
if ( d_data->orientation == Qt::Horizontal )
|
||
|
center.setX( markerPos );
|
||
|
else
|
||
|
center.setY( markerPos );
|
||
|
|
||
|
QRect rect;
|
||
|
rect.setSize( qwtHandleSize( d_data->handleSize,
|
||
|
d_data->orientation, d_data->hasTrough ) );
|
||
|
rect.moveCenter( center );
|
||
|
|
||
|
return rect;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\return Bounding rectangle of the slider - without the scale
|
||
|
*/
|
||
|
QRect QwtSlider::sliderRect() const
|
||
|
{
|
||
|
return d_data->sliderRect;
|
||
|
}
|