File indexing completed on 2023-05-30 11:30:51

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 <KLocalizedString>
0024 
0025 #include <QAction>
0026 #include <QContextMenuEvent>
0027 #include <QMenu>
0028 #include <QPainter>
0029 #include <QStyle>
0030 #include <QStyleOptionSlider>
0031 
0032 Slider::Slider( Qt::Orientation orientation, uint max, QWidget *parent )
0033     : QSlider( orientation, parent )
0034 {
0035     setMouseTracking( true );
0036     setRange( 0, max );
0037     setAttribute( Qt::WA_NoMousePropagation, true );
0038     setAttribute( Qt::WA_Hover, true );
0039     if ( orientation == Qt::Vertical )
0040     {
0041         setInvertedAppearance( true );
0042         setInvertedControls( true );
0043     }
0044 }
0045 
0046 QRectF
0047 Slider::sliderHandleRect( const QRectF &slider, qreal percent ) const
0048 {
0049     QRectF rect;
0050     const bool inverse = ( orientation() == Qt::Horizontal ) ?
0051                          ( invertedAppearance() != (layoutDirection() == Qt::RightToLeft) ) :
0052                          ( !invertedAppearance() );
0053 
0054     if(m_usingCustomStyle)
0055     {
0056         rect = The::svgHandler()->sliderKnobRect( slider, percent, inverse );
0057     }
0058     else
0059     {
0060         if ( inverse )
0061             percent = 1.0 - percent;
0062         const int handleSize = style()->pixelMetric( QStyle::PM_SliderControlThickness );
0063         rect = QRect( 0, 0, handleSize, handleSize );
0064         rect.moveTo( slider.x() + qRound( ( slider.width() - handleSize ) * percent ), slider.y() + 1 );
0065     }
0066 
0067     return rect;
0068 }
0069 
0070 void
0071 Slider::wheelEvent( QWheelEvent *e )
0072 {
0073     if( orientation() == Qt::Vertical )
0074     {
0075         // Will be handled by the parent widget
0076         e->ignore();
0077         return;
0078     }
0079 
0080     // Position Slider (horizontal)
0081     // only used for progress slider now!
0082     int step = e->angleDelta().y() * 24;
0083     int nval = value() + step;
0084     nval = qMax(nval, minimum());
0085     nval = qMin(nval, maximum());
0086 
0087     QSlider::setValue( nval );
0088 }
0089 
0090 void Slider::paintCustomSlider( QPainter *p )
0091 {
0092     qreal percent = 0.0;
0093     if ( maximum() > minimum() )
0094         percent = ((qreal)value()) / ( maximum() - minimum() );
0095     QStyleOptionSlider opt;
0096     initStyleOption( &opt );
0097     if ( this->isSliderDown() ||
0098         ( underMouse() && sliderHandleRect( rect(), percent ).contains( mapFromGlobal(QCursor::pos()) ) ) )
0099     {
0100         opt.activeSubControls |= QStyle::SC_SliderHandle;
0101     }
0102     The::svgHandler()->setDevicePixelRatioF(devicePixelRatioF());
0103     The::svgHandler()->paintCustomSlider( p, &opt, percent );
0104 }
0105 
0106 //////////////////////////////////////////////////////////////////////////////////////////
0107 /// CLASS VolumeSlider
0108 //////////////////////////////////////////////////////////////////////////////////////////
0109 
0110 VolumeSlider::VolumeSlider( uint max, QWidget *parent, bool customStyle )
0111     : Slider( customStyle ? Qt::Horizontal : Qt::Vertical, max, parent )
0112 {
0113     m_usingCustomStyle = customStyle;
0114     setFocusPolicy( Qt::NoFocus );
0115     setInvertedAppearance( false );
0116     setInvertedControls( false );
0117 
0118     connect(this, &QAbstractSlider::valueChanged, this, &VolumeSlider::emitVolumeChanged);
0119 }
0120 
0121 void
0122 VolumeSlider::contextMenuEvent( QContextMenuEvent *e )
0123 {
0124     QMenu menu;
0125     menu.setTitle(   i18n( "Volume" ) );
0126     menu.addAction(  i18n(   "100%" ) )->setData( 100 );
0127     menu.addAction(  i18n(    "80%" ) )->setData(  80 );
0128     menu.addAction(  i18n(    "60%" ) )->setData(  60 );
0129     menu.addAction(  i18n(    "40%" ) )->setData(  40 );
0130     menu.addAction(  i18n(    "20%" ) )->setData(  20 );
0131     menu.addAction(  i18n(     "0%" ) )->setData(   0 );
0132 
0133     QAction* a = menu.exec( mapToGlobal( e->pos() ) );
0134     if( a )
0135     {
0136         const int n = a->data().toInt();
0137         if( n >= 0 )
0138         {
0139             this->setValue( n );
0140         }
0141     }
0142 }
0143 
0144 void
0145 VolumeSlider::wheelEvent( QWheelEvent *e )
0146 {
0147     static const int volumeSensitivity = 30;
0148     const uint step = e->angleDelta().y() / volumeSensitivity;
0149     this->setValue( this->value() + step );
0150 }
0151 
0152 void
0153 VolumeSlider::paintEvent( QPaintEvent *event )
0154 {
0155     if( m_usingCustomStyle )
0156     {
0157         QPainter p( this );
0158         paintCustomSlider( &p );
0159         p.end();
0160         return;
0161     }
0162 
0163     Slider::paintEvent( event );
0164 }
0165 
0166 void
0167 VolumeSlider::emitVolumeChanged( int value )
0168 {
0169     emit volumeChanged( float( value ) / float( maximum() ) );
0170 }
0171 
0172 
0173 //////////////////////////////////////////////////////////////////////////////////////////
0174 ////////////////////////////////// TIMESLIDER ////////////////////////////////////////////
0175 //////////////////////////////////////////////////////////////////////////////////////////
0176 
0177 TimeSlider::TimeSlider( QWidget *parent )
0178     : Slider( Qt::Horizontal, 0, parent )
0179     , m_knobX( 0.0 )
0180 {
0181     m_usingCustomStyle = true;
0182     setFocusPolicy( Qt::NoFocus );
0183 }
0184 
0185 void
0186 TimeSlider::paintEvent( QPaintEvent *pe )
0187 {
0188     QPainter p( this );
0189     p.setClipRegion( pe->region() );
0190     paintCustomSlider( &p );
0191     p.end();
0192 }
0193 
0194 void TimeSlider::sliderChange( SliderChange change )
0195 {
0196     if ( change == SliderValueChange || change == SliderRangeChange )
0197     {
0198         int oldKnobX = m_knobX;
0199         qreal percent = 0.0;
0200         if ( maximum() > minimum() )
0201             percent = ((qreal)value()) / ( maximum() - minimum() );
0202         QRectF knob = sliderHandleRect( rect(), percent );
0203         m_knobX = knob.x();
0204 
0205         if (oldKnobX < m_knobX)
0206             update( oldKnobX, knob.y(), knob.right() + 1 - oldKnobX, knob.height() );
0207         else if (oldKnobX > m_knobX)
0208             update( m_knobX, knob.y(), oldKnobX + knob.width(), knob.height() );
0209     }
0210     else
0211         Slider::sliderChange( change ); // calls update()
0212 }