/*************************************************************************** amarokslider.cpp - description ------------------- begin : Dec 15 2003 copyright : (C) 2003 by Mark Kretschmann email : markey@web.de copyright : (C) 2005 by Gábor Lehel email : illissius@gmail.com ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "sliderwidget.h" #include #include #include #include #include #include #include #include #include #include #include #include Amarok::Slider::Slider( Qt::Orientation orientation, QWidget *parent, uint max ) : QSlider( orientation, parent ) , m_sliding( false ) , m_outside( false ) , m_prevValue( 0 ) { setRange( 0, max ); } void Amarok::Slider::wheelEvent( QWheelEvent *e ) { if( orientation() == Qt::Vertical ) { // Will be handled by the parent widget e->ignore(); return; } // Position Slider (horizontal) int step = e->delta() * 1500 / 18; int nval = QSlider::value() + step; nval = qMax(nval, minimum()); nval = qMin(nval, maximum()); QSlider::setValue( nval ); emit sliderReleased( value() ); } void Amarok::Slider::mouseMoveEvent( QMouseEvent *e ) { if ( m_sliding ) { //feels better, but using set value of 20 is bad of course QRect rect( -20, -20, width()+40, height()+40 ); if ( orientation() == Qt::Horizontal && !rect.contains( e->pos() ) ) { if ( !m_outside ) QSlider::setValue( m_prevValue ); m_outside = true; } else { m_outside = false; slideEvent( e ); emit sliderMoved( value() ); } } else QSlider::mouseMoveEvent( e ); } void Amarok::Slider::slideEvent( QMouseEvent *e ) { QStyleOptionSlider option; initStyleOption(&option); QRect sliderRect(style()->subControlRect(QStyle::CC_Slider, &option, QStyle::SC_SliderHandle, this)); QSlider::setValue( orientation() == Qt::Horizontal ? ((QApplication::layoutDirection() == Qt::RightToLeft) ? QStyle::sliderValueFromPosition(minimum(), maximum(), width() - (e->pos().x() - sliderRect.width()/2), width() + sliderRect.width(), true ) : QStyle::sliderValueFromPosition(minimum(), maximum(), e->pos().x() - sliderRect.width()/2, width() - sliderRect.width() ) ) : QStyle::sliderValueFromPosition(minimum(), maximum(), e->pos().y() - sliderRect.height()/2, height() - sliderRect.height() ) ); } void Amarok::Slider::mousePressEvent( QMouseEvent *e ) { QStyleOptionSlider option; initStyleOption(&option); QRect sliderRect(style()->subControlRect(QStyle::CC_Slider, &option, QStyle::SC_SliderHandle, this)); m_sliding = true; m_prevValue = QSlider::value(); if ( !sliderRect.contains( e->pos() ) ) mouseMoveEvent( e ); } void Amarok::Slider::mouseReleaseEvent( QMouseEvent* ) { if( !m_outside && QSlider::value() != m_prevValue ) emit sliderReleased( value() ); m_sliding = false; m_outside = false; } void Amarok::Slider::setValue( int newValue ) { //don't adjust the slider while the user is dragging it! if ( !m_sliding || m_outside ) QSlider::setValue( adjustValue( newValue ) ); else m_prevValue = newValue; } ////////////////////////////////////////////////////////////////////////////////////////// /// CLASS PrettySlider ////////////////////////////////////////////////////////////////////////////////////////// #define THICKNESS 7 #define MARGIN 3 Amarok::PrettySlider::PrettySlider( Qt::Orientation orientation, SliderMode mode, QWidget *parent, uint max ) : Amarok::Slider( orientation, parent, max ) , m_mode( mode ) { if( m_mode == Pretty) { setFocusPolicy( Qt::NoFocus ); } } void Amarok::PrettySlider::mousePressEvent( QMouseEvent *e ) { Amarok::Slider::mousePressEvent( e ); slideEvent( e ); } void Amarok::PrettySlider::slideEvent( QMouseEvent *e ) { if( m_mode == Pretty ) QSlider::setValue( orientation() == Qt::Horizontal ? QStyle::sliderValueFromPosition(minimum(), maximum(), e->pos().x(), width()-2 ) : QStyle::sliderValueFromPosition(minimum(), maximum(), e->pos().y(), height()-2 ) ); else Amarok::Slider::slideEvent( e ); } namespace Amarok { namespace ColorScheme { extern QColor Background; extern QColor Foreground; } } #if 0 /** these functions aren't required in our fixed size world, but they may become useful one day **/ QSize Amarok::PrettySlider::minimumSizeHint() const { return sizeHint(); } QSize Amarok::PrettySlider::sizeHint() const { constPolish(); return (orientation() == Horizontal ? QSize( maxValue(), THICKNESS + MARGIN ) : QSize( THICKNESS + MARGIN, maxValue() )).expandedTo( QApplit ication::globalStrut() ); } #endif ////////////////////////////////////////////////////////////////////////////////////////// /// CLASS VolumeSlider ////////////////////////////////////////////////////////////////////////////////////////// Amarok::VolumeSlider::VolumeSlider( QWidget *parent, uint max ) : Amarok::Slider( Qt::Horizontal, parent, max ) , m_animCount( 0 ) , m_animTimer( new QTimer( this ) ) , m_pixmapInset( QPixmap( ":volumeslider-inset.png" )) { setFocusPolicy( Qt::NoFocus ); // BEGIN Calculate handle animation pixmaps for mouse-over effect QImage pixmapHandle ( ":volumeslider-handle.png" ); QImage pixmapHandleGlow( ":volumeslider-handle_glow.png" ); float opacity = 0.0; const float step = 1.0 / ANIM_MAX; QImage dst; for ( int i = 0; i < ANIM_MAX; ++i ) { dst = pixmapHandle.copy(); QPainter p(&dst); p.setOpacity(opacity); p.drawImage(0, 0, pixmapHandleGlow); p.end(); m_handlePixmaps.append( QPixmap::fromImage( dst ) ); opacity += step; } // END generateGradient(); setMinimumWidth( m_pixmapInset.width() ); setMinimumHeight( m_pixmapInset.height() ); connect( m_animTimer, SIGNAL( timeout() ), this, SLOT( slotAnimTimer() ) ); } void Amarok::VolumeSlider::generateGradient() { const QImage mask( ":volumeslider-gradient.png" ); QImage gradient_image(mask.size(), QImage::Format_ARGB32_Premultiplied); QPainter p(&gradient_image); QLinearGradient gradient(gradient_image.rect().topLeft(), gradient_image.rect().topRight()); gradient.setColorAt(0, palette().color(QPalette::Background)); gradient.setColorAt(1, palette().color(QPalette::Highlight)); p.fillRect(gradient_image.rect(), QBrush(gradient)); p.setCompositionMode(QPainter::CompositionMode_DestinationIn); p.drawImage(0, 0, mask); p.end(); m_pixmapGradient = QPixmap::fromImage(gradient_image); } void Amarok::VolumeSlider::slotAnimTimer() //SLOT { if ( m_animEnter ) { m_animCount++; update(); if ( m_animCount == ANIM_MAX - 1 ) m_animTimer->stop(); } else { m_animCount--; update(); if ( m_animCount == 0 ) m_animTimer->stop(); } } void Amarok::VolumeSlider::mousePressEvent( QMouseEvent *e ) { if( e->button() != Qt::RightButton ) { Amarok::Slider::mousePressEvent( e ); slideEvent( e ); } } void Amarok::VolumeSlider::contextMenuEvent( QContextMenuEvent *e ) { QMap values; QMenu menu; menu.setTitle("Volume"); values[menu.addAction("100%" )] = 100; values[menu.addAction("80%" )] = 80; values[menu.addAction("60%" )] = 60; values[menu.addAction("40%" )] = 40; values[menu.addAction("20%" )] = 20; values[menu.addAction("0%" )] = 0; QAction* ret = menu.exec( mapToGlobal( e->pos() ) ); if( ret ) { QSlider::setValue( values[ret] ); emit sliderReleased( values[ret] ); } } void Amarok::VolumeSlider::slideEvent( QMouseEvent *e ) { QSlider::setValue( QStyle::sliderValueFromPosition(minimum(), maximum(), e->pos().x(), width()-2 ) ); } void Amarok::VolumeSlider::wheelEvent( QWheelEvent *e ) { const uint step = e->delta() / 10; QSlider::setValue( QSlider::value() + step ); emit sliderReleased( value() ); } void Amarok::VolumeSlider::paintEvent( QPaintEvent * ) { QPainter p(this); const int padding = 7; const int offset = int( double( ( width() - 2 * padding ) * value() ) / maximum() ); p.drawPixmap(0, 0, m_pixmapGradient, 0, 0, offset + padding, 0); p.drawPixmap(0, 0, m_pixmapInset); p.drawPixmap(offset - m_handlePixmaps[0].width() / 2 + padding, 0, m_handlePixmaps[m_animCount]); // Draw percentage number p.setPen( palette().color( QPalette::Disabled, QPalette::Text ).dark() ); QFont font; font.setPixelSize( 9 ); p.setFont( font ); const QRect rect( 0, 0, 34, 15 ); p.drawText( rect, Qt::AlignRight | Qt::AlignVCenter, QString::number( value() ) + '%' ); } void Amarok::VolumeSlider::enterEvent( QEvent* ) { m_animEnter = true; m_animCount = 0; m_animTimer->start( ANIM_INTERVAL ); } void Amarok::VolumeSlider::leaveEvent( QEvent* ) { // This can happen if you enter and leave the widget quickly if ( m_animCount == 0 ) m_animCount = 1; m_animEnter = false; m_animTimer->start( ANIM_INTERVAL ); } void Amarok::VolumeSlider::paletteChange( const QPalette& ) { generateGradient(); }