diff options
Diffstat (limited to 'experimental/tqtinterface/qt4/src/widgets/tqslider.cpp')
-rw-r--r-- | experimental/tqtinterface/qt4/src/widgets/tqslider.cpp | 921 |
1 files changed, 921 insertions, 0 deletions
diff --git a/experimental/tqtinterface/qt4/src/widgets/tqslider.cpp b/experimental/tqtinterface/qt4/src/widgets/tqslider.cpp new file mode 100644 index 000000000..9d3ece2fd --- /dev/null +++ b/experimental/tqtinterface/qt4/src/widgets/tqslider.cpp @@ -0,0 +1,921 @@ +/**************************************************************************** +** +** Implementation of TQSlider class +** +** Created : 961019 +** +** Copyright (C) 2010 Timothy Pearson and (C) 1992-2008 Trolltech ASA. +** +** This file is part of the widgets module of the TQt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.TQPL +** included in the packaging of this file. Licensees holding valid TQt +** Commercial licenses may use this file in accordance with the TQt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "tqslider.h" +#ifndef TQT_NO_SLIDER +#include "tqpainter.h" +#include "tqdrawutil.h" +#include "tqtimer.h" +#include "tqbitmap.h" +#include "tqapplication.h" +#include "tqstyle.h" +#if defined(TQT_ACCESSIBILITY_SUPPORT) +#include "tqaccessible.h" +#endif + +static const int thresholdTime = 300; +static const int repeatTime = 100; + +struct TQSliderPrivate +{ + // ### move these to TQSlider in TQt 4.0 + int sliderStartVal; + TQSliderPrivate() : sliderStartVal( 0 ) { } +}; + + +/*! + \class TQSlider + \brief The TQSlider widget provides a vertical or horizontal slider. + + \ingroup basic + \mainclass + + The slider is the classic widget for controlling a bounded value. + It lets the user move a slider along a horizontal or vertical + groove and translates the slider's position into an integer value + within the legal range. + + TQSlider inherits TQRangeControl, which provides the "integer" side + of the slider. setRange() and value() are likely to be used by + practically all slider users; see the \l TQRangeControl + documentation for information about the many other functions that + class provides. + + The main functions offered by the slider itself are tickmark and + orientation control; you can use setTickmarks() to indicate where + you want the tickmarks to be, setTickInterval() to indicate how + many of them you want and setOrientation() to indicate whether the + slider is to be horizontal or vertical. + + A slider accepts focus on Tab and uses the mouse wheel and a + suitable keyboard interface. + + <img src=qslider-m.png> <img src=qslider-w.png> + + \important setRange + + \sa TQScrollBar TQSpinBox + \link guibooks.html#fowler GUI Design Handbook: Slider\endlink +*/ + + +/*! + \enum TQSlider::TickSetting + + This enum specifies where the tickmarks are to be drawn relative + to the slider's groove and the handle the user moves. + + \value NoMarks do not draw any tickmarks. + \value Both draw tickmarks on both sides of the groove. + \value Above draw tickmarks above the (horizontal) slider + \value Below draw tickmarks below the (horizontal) slider + \value Left draw tickmarks to the left of the (vertical) slider + \value Right draw tickmarks to the right of the (vertical) slider +*/ + + +/*! + Constructs a vertical slider. + + The \a tqparent and \a name arguments are sent on to the TQWidget + constructor. +*/ + +TQSlider::TQSlider( TQWidget *tqparent, const char *name ) + : TQWidget( tqparent, name ) +{ + orient = Qt::Vertical; + init(); +} + +/*! + Constructs a slider. + + The \a orientation must be \l Qt::Vertical or \l Qt::Horizontal. + + The \a tqparent and \a name arguments are sent on to the TQWidget + constructor. +*/ + +TQSlider::TQSlider( Qt::Orientation orientation, TQWidget *tqparent, const char *name ) + : TQWidget( tqparent, name ) +{ + orient = orientation; + init(); +} + +/*! + Constructs a slider whose value can never be smaller than \a + minValue or greater than \a maxValue, whose page step size is \a + pageStep and whose value is initially \a value (which is + guaranteed to be in range using bound()). + + If \a orientation is \c Qt::Vertical the slider is vertical and if it + is \c Qt::Horizontal the slider is horizontal. + + The \a tqparent and \a name arguments are sent on to the TQWidget + constructor. +*/ + +TQSlider::TQSlider( int minValue, int maxValue, int pageStep, + int value, Qt::Orientation orientation, + TQWidget *tqparent, const char *name ) + : TQWidget( tqparent, name ), + TQRangeControl( minValue, maxValue, 1, pageStep, value ) +{ + orient = orientation; + init(); + sliderVal = value; +} + +/*! + Destructor. +*/ +TQSlider::~TQSlider() +{ + delete d; +} + +void TQSlider::init() +{ + d = new TQSliderPrivate; + timer = 0; + sliderPos = 0; + sliderVal = 0; + clickOffset = 0; + state = Idle; + track = TRUE; + ticks = NoMarks; + tickInt = 0; + setFocusPolicy( Qt::TabFocus ); + initTicks(); + + TQSizePolicy sp( TQSizePolicy::Expanding, TQSizePolicy::Fixed ); + if ( orient == Qt::Vertical ) + sp.transpose(); + tqsetSizePolicy( sp ); + clearWState( TQt::WState_OwnSizePolicy ); +} + + +/* + Does what's needed when someone changes the tickmark status. +*/ + +void TQSlider::initTicks() +{ + tickOffset = tqstyle().tqpixelMetric( TQStyle::PM_SliderTickmarkOffset, this ); +} + + +/*! + \property TQSlider::tracking + \brief whether slider tracking is enabled + + If tracking is enabled (the default), the slider emits the + valueChanged() signal whenever the slider is being dragged. If + tracking is disabled, the slider emits the valueChanged() signal + when the user releases the mouse button (unless the value happens + to be the same as before). +*/ + +void TQSlider::setTracking( bool enable ) +{ + track = enable; +} + + +/*! + \fn void TQSlider::valueChanged( int value ) + + This signal is emitted when the slider value is changed, with the + new slider \a value as its argument. +*/ + +/*! + \fn void TQSlider::sliderPressed() + + This signal is emitted when the user presses the slider with the + mouse. +*/ + +/*! + \fn void TQSlider::sliderMoved( int value ) + + This signal is emitted when the slider is dragged, with the new + slider \a value as its argument. +*/ + +/*! + \fn void TQSlider::sliderReleased() + + This signal is emitted when the user releases the slider with the mouse. +*/ + +/* + Calculates slider position corresponding to value \a v. +*/ + +int TQSlider::positionFromValue( int v ) const +{ + int a = available(); + int x = TQRangeControl::positionFromValue( v, a ); + if ( orient == Qt::Horizontal && TQApplication::reverseLayout() ) + x = a - x; + return x; +} + +/* + Returns the available space in which the slider can move. +*/ + +int TQSlider::available() const +{ + return tqstyle().tqpixelMetric( TQStyle::PM_SliderSpaceAvailable, this ); +} + +/* + Calculates a value corresponding to slider position \a p. +*/ + +int TQSlider::valueFromPosition( int p ) const +{ + int a = available(); + int x = TQRangeControl::valueFromPosition( p, a ); + if ( orient == Qt::Horizontal && TQApplication::reverseLayout() ) + x = maxValue() + minValue() - x; + return x; +} + +/*! + Implements the virtual TQRangeControl function. +*/ + +void TQSlider::rangeChange() +{ + int newPos = positionFromValue( value() ); + if ( newPos != sliderPos ) { + reallyMoveSlider( newPos ); + } +} + +/*! + Implements the virtual TQRangeControl function. +*/ + +void TQSlider::valueChange() +{ + if ( sliderVal != value() ) { + int newPos = positionFromValue( value() ); + sliderVal = value(); + reallyMoveSlider( newPos ); + } + emit valueChanged(value()); +#if defined(TQT_ACCESSIBILITY_SUPPORT) + TQAccessible::updateAccessibility( this, 0, TQAccessible::ValueChanged ); +#endif +} + + +/*! + \reimp +*/ +void TQSlider::resizeEvent( TQResizeEvent * ) +{ + rangeChange(); + initTicks(); +} + + +/*! + Reimplements the virtual function TQWidget::setPalette(). + + Sets the background color to the mid color for Motif style sliders + using palette \a p. +*/ + +void TQSlider::setPalette( const TQPalette &p ) +{ + TQWidget::setPalette( p ); +} + + + +/*! + \property TQSlider::orientation + \brief the slider's orientation + + The orientation must be \l Qt::Vertical (the default) or \l + Qt::Horizontal. +*/ + +void TQSlider::setOrientation( Qt::Orientation orientation ) +{ + if ( orientation == orient ) + return; + + if ( !testWState( TQt::WState_OwnSizePolicy ) ) { + TQSizePolicy sp = sizePolicy(); + sp.transpose(); + tqsetSizePolicy( sp ); + clearWState( TQt::WState_OwnSizePolicy ); + } + + orient = orientation; + + rangeChange(); + update(); +} + +/*! + \fn int TQSlider::sliderStart() const + + Returns the start position of the slider. +*/ + + +/*! + Returns the slider handle rectangle. (This is the visual marker + that the user can move.) +*/ + +TQRect TQSlider::sliderRect() const +{ + return tqstyle().querySubControlMetrics( TQStyle::CC_Slider, this, + TQStyle::SC_SliderHandle ); +} + +/* + Performs the actual moving of the slider. +*/ + +void TQSlider::reallyMoveSlider( int newPos ) +{ + TQRegion oldR(sliderRect()); + sliderPos = newPos; + TQRegion newR(sliderRect()); + + /* just the one tqrepaint if no background */ + if (backgroundMode() == TQt::NoBackground) + tqrepaint(newR | oldR, FALSE); + else { + tqrepaint(oldR.subtract(newR)); + tqrepaint(newR, FALSE); + } +} + + +/*! + \reimp +*/ +void TQSlider::paintEvent( TQPaintEvent * ) +{ + TQPainter p( this ); + + TQStyle::SFlags flags = TQStyle::Style_Default; + if (isEnabled()) + flags |= TQStyle::Style_Enabled; + if (hasFocus()) + flags |= TQStyle::Style_HasFocus; + + TQStyle::SCFlags sub = TQStyle::SC_SliderGroove | TQStyle::SC_SliderHandle; + if ( tickmarks() != NoMarks ) + sub |= TQStyle::SC_SliderTickmarks; + + tqstyle().tqdrawComplexControl( TQStyle::CC_Slider, &p, this, rect(), tqcolorGroup(), + flags, sub, state == Dragging ? TQStyle::SC_SliderHandle : TQStyle::SC_None ); +} + + +/*! + \reimp +*/ +void TQSlider::mousePressEvent( TQMouseEvent *e ) +{ + int slideLength = tqstyle().tqpixelMetric( TQStyle::PM_SliderLength, this ); + resetState(); + d->sliderStartVal = sliderVal; + TQRect r = sliderRect(); + + if ( e->button() == Qt::RightButton ) + return; + + if ( r.tqcontains( e->pos() ) ) { + state = Dragging; + clickOffset = (TQCOORD)( goodPart( e->pos() ) - sliderPos ); + emit sliderPressed(); + } else if ( e->button() == Qt::MidButton ) { + int pos = goodPart( e->pos() ); + moveSlider( pos - slideLength / 2 ); + state = Dragging; + clickOffset = slideLength / 2; + } else if ( (orient == Qt::Horizontal && e->pos().x() < r.left()) //### goodPart + || (orient == Qt::Vertical && e->pos().y() < r.top()) ) { + if ( orient == Qt::Horizontal && TQApplication::reverseLayout() ) { + state = TimingUp; + addPage(); + } else { + state = TimingDown; + subtractPage(); + } + if ( !timer ) + timer = new TQTimer( this ); + connect( timer, TQT_SIGNAL(timeout()), TQT_SLOT(repeatTimeout()) ); + timer->start( thresholdTime, TRUE ); + } else if ( (orient == Qt::Horizontal && e->pos().x() > r.right()) //### goodPart + || (orient == Qt::Vertical && e->pos().y() > r.bottom()) ) { + if ( orient == Qt::Horizontal && TQApplication::reverseLayout() ) { + state = TimingDown; + subtractPage(); + } else { + state = TimingUp; + addPage(); + } + if ( !timer ) + timer = new TQTimer( this ); + connect( timer, TQT_SIGNAL(timeout()), TQT_SLOT(repeatTimeout()) ); + timer->start( thresholdTime, TRUE ); + } + update( sliderRect() ); +} + +/*! + \reimp +*/ +void TQSlider::mouseMoveEvent( TQMouseEvent *e ) +{ + if ( state != Dragging ) + return; + + TQRect r = rect(); + int m = tqstyle().tqpixelMetric( TQStyle::PM_MaximumDragDistance, + this ); + if ( m >= 0 ) { + if ( orientation() == Qt::Horizontal ) + r.setRect( r.x() - m, r.y() - 2*m/3, + r.width() + 2*m, r.height() + 3*m ); + else + r.setRect( r.x() - 2*m/3, r.y() - m, + r.width() + 3*m, r.height() + 2*m ); + if ( !r.tqcontains( e->pos() ) ) { + moveSlider( positionFromValue(d->sliderStartVal) ); + return; + } + } + + int pos = goodPart( e->pos() ); + moveSlider( pos - clickOffset ); +} + +/*! + \reimp +*/ +#ifndef TQT_NO_WHEELEVENT +void TQSlider::wheelEvent( TQWheelEvent * e ) +{ + if ( e->orientation() != orientation() && !TQT_TQRECT_OBJECT(rect()).tqcontains(e->pos()) ) + return; + + static float offset = 0; + static TQSlider* offset_owner = 0; + if (offset_owner != this){ + offset_owner = this; + offset = 0; + } + offset += -e->delta()*TQMAX(pageStep(),lineStep())/120; + if (TQABS(offset)<1) + return; + setValue( value() + int(offset) ); + offset -= int(offset); + e->accept(); +} +#endif + +/*! + \reimp +*/ +void TQSlider::mouseReleaseEvent( TQMouseEvent * ) +{ + resetState(); + update( sliderRect() ); +} + +/*! + \reimp +*/ +void TQSlider::focusInEvent( TQFocusEvent * e) +{ + TQWidget::focusInEvent( e ); +} + +/*! + \reimp +*/ +void TQSlider::focusOutEvent( TQFocusEvent * e ) +{ + TQWidget::focusOutEvent( e ); +} + +/*! + Moves the left (or top) edge of the slider to position \a pos. The + slider is actually moved to the step position nearest the given \a + pos. +*/ + +void TQSlider::moveSlider( int pos ) +{ + int a = available(); + int newPos = TQMIN( a, TQMAX( 0, pos ) ); + int newVal = valueFromPosition( newPos ); + if (tqstyle().tqstyleHint(TQStyle::SH_Slider_SnapToValue, this)) + newPos = positionFromValue( newVal ); + if ( sliderPos != newPos ) + reallyMoveSlider( newPos ); + if ( sliderVal != newVal ) { + sliderVal = newVal; + emit sliderMoved( sliderVal ); + } + if ( tracking() && sliderVal != value() ) + setValue( sliderVal ); + +} + + +/* + Resets all state information and stops the timer. +*/ + +void TQSlider::resetState() +{ + if ( timer ) { + timer->stop(); + timer->disconnect(); + } + switch ( state ) { + case TimingUp: + case TimingDown: + break; + case Dragging: { + setValue( valueFromPosition( sliderPos ) ); + emit sliderReleased(); + break; + } + case Idle: + break; + default: + qWarning("TQSlider: (%s) in wrong state", name( "unnamed" ) ); + } + state = Idle; +} + + +/*! + \reimp +*/ +void TQSlider::keyPressEvent( TQKeyEvent *e ) +{ + bool sloppy = bool(tqstyle().tqstyleHint(TQStyle::SH_Slider_SloppyKeyEvents, this)); + switch ( e->key() ) { + case Qt::Key_Left: + if ( sloppy || orient == Qt::Horizontal ) { + if (TQApplication::reverseLayout()) + addLine(); + else + subtractLine(); + } + break; + case Qt::Key_Right: + if ( sloppy || orient == Qt::Horizontal ) { + if (TQApplication::reverseLayout()) + subtractLine(); + else + addLine(); + } + break; + case Qt::Key_Up: + if ( sloppy || orient == Qt::Vertical ) + subtractLine(); + break; + case Qt::Key_Down: + if ( sloppy || orient == Qt::Vertical ) + addLine(); + break; + case TQt::Key_Prior: + subtractPage(); + break; + case TQt::Key_Next: + addPage(); + break; + case Qt::Key_Home: + setValue( minValue() ); + break; + case Qt::Key_End: + setValue( maxValue() ); + break; + default: + e->ignore(); + return; + } +} + +void TQSlider::setValue( int value ) +{ + TQRangeControl::setValue( value ); +#if defined(TQT_ACCESSIBILITY_SUPPORT) + TQAccessible::updateAccessibility( this, 0, TQAccessible::ValueChanged ); +#endif +} + + +/*! \reimp +*/ + +void TQSlider::addLine() +{ + TQRangeControl::addLine(); +} + +/*! \reimp +*/ + +void TQSlider::subtractLine() +{ + TQRangeControl::subtractLine(); +} + +/*! + Moves the slider one pageStep() up or right. +*/ + +void TQSlider::addStep() +{ + addPage(); +} + + +/*! + Moves the slider one pageStep() down or left. +*/ + +void TQSlider::subtractStep() +{ + subtractPage(); +} + + +/* + Waits for autorepeat. +*/ + +void TQSlider::repeatTimeout() +{ + TQ_ASSERT( timer ); + timer->disconnect(); + if ( state == TimingDown ) + connect( timer, TQT_SIGNAL(timeout()), TQT_SLOT(subtractStep()) ); + else if ( state == TimingUp ) + connect( timer, TQT_SIGNAL(timeout()), TQT_SLOT(addStep()) ); + timer->start( repeatTime, FALSE ); +} + + +/* + Returns the relevant dimension of \a p. +*/ + +int TQSlider::goodPart( const TQPoint &p ) const +{ + return (orient == Qt::Horizontal) ? p.x() : p.y(); +} + +/*! + \reimp +*/ +TQSize TQSlider::tqsizeHint() const +{ + constPolish(); + const int length = 84, tickSpace = 5; + int thick = tqstyle().tqpixelMetric( TQStyle::PM_SliderThickness, this ); + if ( ticks & Above ) + thick += tickSpace; + if ( ticks & Below ) + thick += tickSpace; + int w = thick, h = length; + if ( orient == Qt::Horizontal ) { + w = length; + h = thick; + } + return (tqstyle().tqsizeFromContents(TQStyle::CT_Slider, this, + TQSize(w, h)).expandedTo(TQApplication::globalStrut())); +} + + + +/*! + \reimp +*/ + +TQSize TQSlider::tqminimumSizeHint() const +{ + TQSize s = tqsizeHint(); + int length = tqstyle().tqpixelMetric(TQStyle::PM_SliderLength, this); + if ( orient == Qt::Horizontal ) + s.setWidth( length ); + else + s.setHeight( length ); + + return s; +} + +/*! \fn void TQSlider::tqsetSizePolicy( TQSizePolicy::SizeType, TQSizePolicy::SizeType, bool ) + \reimp +*/ + +/*! \reimp */ +void TQSlider::tqsetSizePolicy( TQSizePolicy sp ) +{ + // ## remove 4.0 + TQWidget::tqsetSizePolicy( sp ); +} + +/*! \reimp */ +TQSizePolicy TQSlider::sizePolicy() const +{ + // ### 4.0 remove this reimplementation + return TQWidget::tqsizePolicy(); +} + +/*! + \property TQSlider::tickmarks + \brief the tickmark settings for this slider + + The valid values are in \l{TQSlider::TickSetting}. The default is + \c NoMarks. + + \sa tickInterval +*/ + +void TQSlider::setTickmarks( TickSetting s ) +{ + ticks = s; + initTicks(); + update(); +} + + +/*! + \property TQSlider::tickInterval + \brief the interval between tickmarks + + This is a value interval, not a pixel interval. If it is 0, the + slider will choose between lineStep() and pageStep(). The initial + value of tickInterval is 0. + + \sa TQRangeControl::lineStep(), TQRangeControl::pageStep() +*/ + +void TQSlider::setTickInterval( int i ) +{ + tickInt = TQMAX( 0, i ); + update(); +} + + +/*! + \reimp +*/ +void TQSlider::styleChange( TQStyle& old ) +{ + TQWidget::styleChange( old ); +} + +/*! + \property TQSlider::minValue + \brief the current minimum value of the slider + + When setting this property, the \l TQSlider::maxValue is adjusted, + if necessary, to ensure that the range remains valid. + + \sa setRange() +*/ +int TQSlider::minValue() const +{ + return TQRangeControl::minValue(); +} + +/*! + \property TQSlider::maxValue + \brief the current maximum value of the slider + + When setting this property, the \l TQSlider::minValue is adjusted, + if necessary, to ensure that the range remains valid. + + \sa setRange() +*/ +int TQSlider::maxValue() const +{ + return TQRangeControl::maxValue(); +} + +void TQSlider::setMinValue( int minVal ) +{ + TQRangeControl::setMinValue( minVal ); +} + +void TQSlider::setMaxValue( int maxVal ) +{ + TQRangeControl::setMaxValue( maxVal ); +} + +/*! + \property TQSlider::lineStep + \brief the current line step + + When setting lineStep, the virtual stepChange() function will be + called if the new line step is different from the previous + setting. + + \sa setSteps() TQRangeControl::pageStep() setRange() +*/ +int TQSlider::lineStep() const +{ + return TQRangeControl::lineStep(); +} + +/*! + \property TQSlider::pageStep + \brief the current page step + + When setting pageStep, the virtual stepChange() function will be + called if the new page step is different from the previous + setting. + + \sa TQRangeControl::setSteps() setLineStep() setRange() +*/ + +int TQSlider::pageStep() const +{ + return TQRangeControl::pageStep(); +} + +void TQSlider::setLineStep( int i ) +{ + setSteps( i, pageStep() ); +} + +void TQSlider::setPageStep( int i ) +{ + setSteps( lineStep(), i ); +} + +/*! + \property TQSlider::value + \brief the current slider value + + \sa TQRangeControl::value() prevValue() +*/ + +int TQSlider::value() const +{ + return TQRangeControl::value(); +} + +#endif |