File indexing completed on 2021-12-21 13:28:00

0001 /**
0002  * Copyright (c) 2003-2009 Mark Kretschmann <kretschmann@kde.org>
0003  * Copyright (c) 2005 Gabor Lehel <illissius@gmail.com>
0004  * Copyright (c) 2008 Dan Meltzer <parallelgrapefruit@gmail.com>
0005  * Copyright (c) 2021 Michael Pyne <mpyne@kde.org>
0006  *
0007  * This program is free software; you can redistribute it and/or modify it under
0008  * the terms of the GNU General Public License as published by the Free Software
0009  * Foundation; either version 2 of the License, or (at your option) any later
0010  * version.
0011  *
0012  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0013  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0014  * PARTICULAR PURPOSE. See the GNU General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU General Public License along with
0017  * this program.  If not, see <http://www.gnu.org/licenses/>.
0018  */
0019 
0020 #include "slider.h"
0021 #include "svghandler.h"
0022 
0023 #include <QIcon>
0024 #include <KLocalizedString>
0025 
0026 #include <QAction>
0027 #include <QContextMenuEvent>
0028 #include <QFontMetrics>
0029 #include <QMenu>
0030 #include <QPainter>
0031 #include <QStyle>
0032 #include <QStyleOptionSlider>
0033 
0034 Slider::Slider( Qt::Orientation orientation, uint max, QWidget *parent )
0035     : QSlider( orientation, parent )
0036 {
0037     setMouseTracking( true );
0038     setRange( 0, max );
0039     setAttribute( Qt::WA_NoMousePropagation, true );
0040     setAttribute( Qt::WA_Hover, true );
0041     if ( orientation == Qt::Vertical )
0042     {
0043         setInvertedAppearance( true );
0044         setInvertedControls( true );
0045     }
0046 }
0047 
0048 QRectF
0049 Slider::sliderHandleRect( const QRectF &slider, qreal percent ) const
0050 {
0051     QRectF rect;
0052     const bool inverse = ( orientation() == Qt::Horizontal ) ?
0053                          ( invertedAppearance() != (layoutDirection() == Qt::RightToLeft) ) :
0054                          ( !invertedAppearance() );
0055 
0056     if(m_usingCustomStyle)
0057     {
0058         rect = The::svgHandler()->sliderKnobRect( slider, percent, inverse );
0059     }
0060     else
0061     {
0062         if ( inverse )
0063             percent = 1.0 - percent;
0064         const int handleSize = style()->pixelMetric( QStyle::PM_SliderControlThickness );
0065         rect = QRect( 0, 0, handleSize, handleSize );
0066         rect.moveTo( slider.x() + qRound( ( slider.width() - handleSize ) * percent ), slider.y() + 1 );
0067     }
0068 
0069     return rect;
0070 }
0071 
0072 void
0073 Slider::wheelEvent( QWheelEvent *e )
0074 {
0075     if( orientation() == Qt::Vertical )
0076     {
0077         // Will be handled by the parent widget
0078         e->ignore();
0079         return;
0080     }
0081 
0082     // Position Slider (horizontal)
0083     // only used for progress slider now!
0084     int step = e->angleDelta().y() * 24;
0085     int nval = value() + step;
0086     nval = qMax(nval, minimum());
0087     nval = qMin(nval, maximum());
0088 
0089     QSlider::setValue( nval );
0090 }
0091 
0092 void Slider::paintCustomSlider( QPainter *p )
0093 {
0094     qreal percent = 0.0;
0095     if ( maximum() > minimum() )
0096         percent = ((qreal)value()) / ( maximum() - minimum() );
0097     QStyleOptionSlider opt;
0098     initStyleOption( &opt );
0099     if ( this->isSliderDown() ||
0100         ( underMouse() && sliderHandleRect( rect(), percent ).contains( mapFromGlobal(QCursor::pos()) ) ) )
0101     {
0102         opt.activeSubControls |= QStyle::SC_SliderHandle;
0103     }
0104     The::svgHandler()->setDevicePixelRatioF(devicePixelRatioF());
0105     The::svgHandler()->paintCustomSlider( p, &opt, percent );
0106 }
0107 
0108 //////////////////////////////////////////////////////////////////////////////////////////
0109 /// CLASS VolumeSlider
0110 //////////////////////////////////////////////////////////////////////////////////////////
0111 
0112 VolumeSlider::VolumeSlider( uint max, QWidget *parent, bool customStyle )
0113     : Slider( customStyle ? Qt::Horizontal : Qt::Vertical, max, parent )
0114 {
0115     m_usingCustomStyle = customStyle;
0116     setFocusPolicy( Qt::NoFocus );
0117     setInvertedAppearance( false );
0118     setInvertedControls( false );
0119 
0120     connect(this, &QAbstractSlider::valueChanged, this, &VolumeSlider::emitVolumeChanged);
0121 }
0122 
0123 void
0124 VolumeSlider::contextMenuEvent( QContextMenuEvent *e )
0125 {
0126     QMenu menu;
0127     menu.setTitle(   i18n( "Volume" ) );
0128     menu.addAction(  i18n(   "100%" ) )->setData( 100 );
0129     menu.addAction(  i18n(    "80%" ) )->setData(  80 );
0130     menu.addAction(  i18n(    "60%" ) )->setData(  60 );
0131     menu.addAction(  i18n(    "40%" ) )->setData(  40 );
0132     menu.addAction(  i18n(    "20%" ) )->setData(  20 );
0133     menu.addAction(  i18n(     "0%" ) )->setData(   0 );
0134 
0135     QAction* a = menu.exec( mapToGlobal( e->pos() ) );
0136     if( a )
0137     {
0138         const int n = a->data().toInt();
0139         if( n >= 0 )
0140         {
0141             this->setValue( n );
0142         }
0143     }
0144 }
0145 
0146 void
0147 VolumeSlider::wheelEvent( QWheelEvent *e )
0148 {
0149     static const int volumeSensitivity = 30;
0150     const uint step = e->angleDelta().y() / volumeSensitivity;
0151     this->setValue( this->value() + step );
0152 }
0153 
0154 void
0155 VolumeSlider::paintEvent( QPaintEvent *event )
0156 {
0157     if( m_usingCustomStyle )
0158     {
0159         QPainter p( this );
0160         paintCustomSlider( &p );
0161         p.end();
0162         return;
0163     }
0164 
0165     Slider::paintEvent( event );
0166 }
0167 
0168 void
0169 VolumeSlider::emitVolumeChanged( int value )
0170 {
0171     emit volumeChanged( float( value ) / float( maximum() ) );
0172 }
0173 
0174 
0175 //////////////////////////////////////////////////////////////////////////////////////////
0176 ////////////////////////////////// TIMESLIDER ////////////////////////////////////////////
0177 //////////////////////////////////////////////////////////////////////////////////////////
0178 
0179 TimeSlider::TimeSlider( QWidget *parent )
0180     : Slider( Qt::Horizontal, 0, parent )
0181     , m_knobX( 0.0 )
0182 {
0183     m_usingCustomStyle = true;
0184     setFocusPolicy( Qt::NoFocus );
0185 }
0186 
0187 void
0188 TimeSlider::paintEvent( QPaintEvent *pe )
0189 {
0190     QPainter p( this );
0191     p.setClipRegion( pe->region() );
0192     paintCustomSlider( &p );
0193     p.end();
0194 }
0195 
0196 void TimeSlider::sliderChange( SliderChange change )
0197 {
0198     if ( change == SliderValueChange || change == SliderRangeChange )
0199     {
0200         int oldKnobX = m_knobX;
0201         qreal percent = 0.0;
0202         if ( maximum() > minimum() )
0203             percent = ((qreal)value()) / ( maximum() - minimum() );
0204         QRectF knob = sliderHandleRect( rect(), percent );
0205         m_knobX = knob.x();
0206 
0207         if (oldKnobX < m_knobX)
0208             update( oldKnobX, knob.y(), knob.right() + 1 - oldKnobX, knob.height() );
0209         else if (oldKnobX > m_knobX)
0210             update( m_knobX, knob.y(), oldKnobX + knob.width(), knob.height() );
0211     }
0212     else
0213         Slider::sliderChange( change ); // calls update()
0214 }