1 /***************************************************************************
2 amarokslider.cpp - description
5 copyright : (C) 2003 by Mark Kretschmann
7 copyright : (C) 2005 by Gábor Lehel
8 email : illissius@gmail.com
9 ***************************************************************************/
11 /***************************************************************************
13 * This program is free software; you can redistribute it and/or modify *
14 * it under the terms of the GNU General Public License as published by *
15 * the Free Software Foundation; either version 2 of the License, or *
16 * (at your option) any later version. *
18 ***************************************************************************/
20 #include "config-amarok.h"
23 #include "amarokconfig.h"
26 #include "enginecontroller.h"
27 #include "sliderwidget.h"
31 #include <QContextMenuEvent>
36 #include <QStyleOptionComplex>
40 #include <kimageeffect.h>
43 #include <kpixmapeffect.h>
44 #include <kstandarddirs.h>
46 Amarok::Slider::Slider( Qt::Orientation orientation
, QWidget
*parent
, uint max
)
47 : QSlider( orientation
, parent
)
56 Amarok::Slider::wheelEvent( QWheelEvent
*e
)
58 if( orientation() == Qt::Vertical
) {
59 // Will be handled by the parent widget
64 // Position Slider (horizontal)
65 int step
= e
->delta() * 1500 / 18;
66 int nval
= QSlider::value() + step
;
67 nval
= qMax(nval
, minimum());
68 nval
= qMin(nval
, maximum());
70 QSlider::setValue( nval
);
72 emit
sliderReleased( value() );
76 Amarok::Slider::mouseMoveEvent( QMouseEvent
*e
)
80 //feels better, but using set value of 20 is bad of course
81 QRect
rect( -20, -20, width()+40, height()+40 );
83 if ( orientation() == Qt::Horizontal
&& !rect
.contains( e
->pos() ) ) {
85 QSlider::setValue( m_prevValue
);
90 emit
sliderMoved( value() );
93 else QSlider::mouseMoveEvent( e
);
97 Amarok::Slider::slideEvent( QMouseEvent
*e
)
99 QStyleOptionComplex
complex;
100 QRect rect
= style()->subControlRect( QStyle::CC_Slider
, &complex , QStyle::SC_SliderHandle
, this );
102 QSlider::setValue( orientation() == Qt::Horizontal
103 ? ((QApplication::isRightToLeft())
104 ? QStyle::sliderValueFromPosition( minimum(), maximum(), width() - (e
->pos().x() - rect
.width()/2), width() + rect
.width() )
105 : QStyle::sliderValueFromPosition( minimum(), maximum(), e
->pos().x() - rect
.width()/2, width() - rect
.width() ) )
106 : QStyle::sliderValueFromPosition( minimum(), maximum(), e
->pos().y() - rect
.height()/2, height() - rect
.height() ) );
110 Amarok::Slider::mousePressEvent( QMouseEvent
*e
)
112 QStyleOptionComplex
complex;
113 QRect rect
= style()->subControlRect( QStyle::CC_Slider
, &complex , QStyle::SC_SliderHandle
, this );
115 m_prevValue
= QSlider::value();
117 if ( !rect
.contains( e
->pos() ) )
122 Amarok::Slider::mouseReleaseEvent( QMouseEvent
* )
124 if( !m_outside
&& QSlider::value() != m_prevValue
)
125 emit
sliderReleased( value() );
132 Amarok::Slider::setValue( int newValue
)
134 //don't adjust the slider while the user is dragging it!
136 if ( !m_sliding
|| m_outside
)
137 QSlider::setValue( adjustValue( newValue
) );
139 m_prevValue
= newValue
;
143 //////////////////////////////////////////////////////////////////////////////////////////
144 /// CLASS PrettySlider
145 //////////////////////////////////////////////////////////////////////////////////////////
150 Amarok::PrettySlider::PrettySlider( Qt::Orientation orientation
, SliderMode mode
,
151 QWidget
*parent
, uint max
)
152 : Amarok::Slider( orientation
, parent
, max
)
154 , m_showingMoodbar( false )
156 if( m_mode
== Pretty
)
158 setWindowFlags( Qt::WNoAutoErase
);
159 setFocusPolicy( Qt::NoFocus
);
162 // We only have to connect this *once*, since our MetaBundle
163 // doesn't get destroyed until we do.
164 connect( &m_bundle
.moodbar(), SIGNAL( jobEvent( int ) ),
165 SLOT( moodbarJobEvent( int ) ) );
167 // We want to know if we should reset our moodbar data
168 connect( App::instance(), SIGNAL( moodbarPrefs( bool, bool, int, bool ) ),
169 SLOT( slotMoodbarPrefs( bool, bool, int, bool ) ) );
174 Amarok::PrettySlider::mousePressEvent( QMouseEvent
*e
)
176 Amarok::Slider::mousePressEvent( e
);
182 Amarok::PrettySlider::slideEvent( QMouseEvent
*e
)
184 if( m_mode
== Pretty
|| m_showingMoodbar
)
185 QSlider::setValue( orientation() == Qt::Horizontal
186 ? QStyle::sliderValueFromPosition( minimum(), maximum(), e
->pos().x(), width()-2 )
187 : QStyle::sliderValueFromPosition( minimum(), maximum(), e
->pos().y(), height()-2 ) );
189 Amarok::Slider::slideEvent( e
);
193 namespace ColorScheme
{
194 extern QColor Background
;
195 extern QColor Foreground
;
200 Amarok::PrettySlider::paintEvent( QPaintEvent
*e
)
202 const int w
= orientation() == Qt::Horizontal
? width() : height();
203 const int pos
= int( double( w
-2 ) / maximum() * Slider::value() );
206 m_showingMoodbar
= ( !m_bundle
.url().isEmpty() &&
207 m_bundle
.moodbar().dataExists() &&
208 AmarokConfig::showMoodbar() );
210 if( m_showingMoodbar
)
212 if( m_mode
== Normal
)
213 h
= (orientation() == Qt::Vertical
? width() : height()) - 2*MARGIN
;
214 mood
= m_bundle
.moodbar().draw( w
, h
);
216 // If we're a Normal PrettySlider and we have no moodbar,
217 // emulate the behavior of Slider
218 else if( m_mode
== Normal
)
220 Amarok::Slider::paintEvent( e
);
226 if ( orientation() == Qt::Vertical
)
228 p
.translate( 0, height()-1 );
229 p
.rotate( -90 ); //90 degrees clockwise
232 if( !m_showingMoodbar
)
234 p
.translate( 0, MARGIN
);
235 p
.setPen( Amarok::ColorScheme::Foreground
);
236 p
.fillRect( 0, 0, pos
, h
, QColor( Amarok::ColorScheme::Background
) );
237 p
.drawRect( 0, 0, w
, h
);
238 p
.translate( 0, -MARGIN
);
242 p
.translate( 0, MARGIN
);
243 p
.drawPixmap( 0, 0, mood
);
244 p
.setPen( Amarok::ColorScheme::Foreground
);
245 p
.drawRect( 0, 0, w
, h
);
246 p
.translate( 0, -MARGIN
);
248 // Larger triangle for the moodbar
252 if( m_mode
== Pretty
)
255 pa
.setPoint( 0, pos
- 3, 1 );
256 pa
.setPoint( 1, pos
+ 3, 1 );
257 pa
.setPoint( 2, pos
, 5 );
258 p
.setBrush( paletteForegroundColor() );
259 p
.drawConvexPolygon( pa
);
262 else if( m_mode
== Normal
)
265 pa
.setPoint( 0, pos
- 5, 1 );
266 pa
.setPoint( 1, pos
+ 5, 1 );
267 pa
.setPoint( 2, pos
, 9 );
268 p
.setBrush( paletteForegroundColor() );
269 p
.drawConvexPolygon( pa
);
275 // This gets called when the moodbar job starts or finishes
277 Amarok::PrettySlider::moodbarJobEvent( int newState
)
279 if( newState
== Moodbar::JobStateSucceeded
)
281 debug() << "moodbarJobEvent: new moodbar data" << endl
;
286 // This gets called when the user presses "Ok" or "Apply" in the
287 // config dialog. Reload our moodbar data, in case it was
288 // permanently disabled before because the moodbar was disabled.
290 Amarok::PrettySlider::slotMoodbarPrefs( bool show
, bool moodier
, int alter
, bool withMusic
)
292 (void) moodier
; (void) alter
; (void) withMusic
;
296 m_bundle
.moodbar().reset();
297 if( !m_bundle
.moodbar().dataExists() )
298 m_bundle
.moodbar().load();
306 // This is called when the track changes / stops / starts
308 Amarok::PrettySlider::newBundle( const MetaBundle
&bundle
)
312 // This is the easiest way to tell if the bundle refers
313 // to a real track, or if we're STOP'd.
314 if( m_bundle
.url().isEmpty() )
317 // It's a real track; get the moodbar data if it's not there
318 if( !m_bundle
.moodbar().dataExists() )
319 m_bundle
.moodbar().load();
327 /** these functions aren't required in our fixed size world,
328 but they may become useful one day **/
331 Amarok::PrettySlider::minimumSizeHint() const
337 Amarok::PrettySlider::sizeHint() const
341 return (orientation() == Qt::Horizontal
342 ? QSize( maximum(), THICKNESS
+ MARGIN
)
343 : QSize( THICKNESS
+ MARGIN
, maximum() )).expandedTo( QApplit
ication::globalStrut() );
347 //////////////////////////////////////////////////////////////////////////////////////////
348 /// CLASS VolumeSlider
349 //////////////////////////////////////////////////////////////////////////////////////////
351 Amarok::VolumeSlider::VolumeSlider( QWidget
*parent
, uint max
)
352 : Amarok::Slider( Qt::Horizontal
, parent
, max
)
354 , m_animTimer( new QTimer( this ) )
355 , m_pixmapInset( QPixmap( KStandardDirs::locate( "data","amarok/images/volumeslider-inset.png" ) ) )
357 setFocusPolicy( Qt::NoFocus
);
359 // BEGIN Calculate handle animation pixmaps for mouse-over effect
360 QImage
pixmapHandle ( KStandardDirs::locate( "data","amarok/images/volumeslider-handle.png" ) );
361 QImage
pixmapHandleGlow( KStandardDirs::locate( "data","amarok/images/volumeslider-handle_glow.png" ) );
364 const float step
= 1.0 / ANIM_MAX
;
366 for ( int i
= 0; i
< ANIM_MAX
; ++i
) {
368 KImageEffect::blend( pixmapHandleGlow
, dst
, opacity
);
369 m_handlePixmaps
.append( QPixmap( dst
) );
376 setMinimumWidth( m_pixmapInset
.width() );
377 setMinimumHeight( m_pixmapInset
.height() );
379 connect( m_animTimer
, SIGNAL( timeout() ), this, SLOT( slotAnimTimer() ) );
383 Amarok::VolumeSlider::generateGradient()
385 //QImage temp( KStandardDirs::locate( "data","amarok/images/volumeslider-gradient.png" ) );
386 //KIconEffect::colorize( temp, colorGroup().highlight(), 1.0 );
388 const QPixmap
temp( KStandardDirs::locate( "data","amarok/images/volumeslider-gradient.png" ) );
389 const QBitmap
mask( temp
.createHeuristicMask() );
391 m_pixmapGradient
= QPixmap( m_pixmapInset
.size() );
392 KPixmapEffect::gradient( m_pixmapGradient
, colorGroup().alternateBase(), colorGroup().highlight(),
393 KPixmapEffect::HorizontalGradient
);
394 m_pixmapGradient
.setMask( mask
);
398 Amarok::VolumeSlider::slotAnimTimer() //SLOT
403 if ( m_animCount
== ANIM_MAX
- 1 )
408 if ( m_animCount
== 0 )
414 Amarok::VolumeSlider::mousePressEvent( QMouseEvent
*e
)
416 if( e
->button() != Qt::RightButton
) {
417 Amarok::Slider::mousePressEvent( e
);
423 Amarok::VolumeSlider::contextMenuEvent( QContextMenuEvent
*e
)
426 menu
.setTitle( i18n( "Volume" ) );
427 menu
.addAction( i18n( "100%" ) )->setData( 100 );
428 menu
.addAction( i18n( "80%" ) )->setData( 80 );
429 menu
.addAction( i18n( "60%" ) )->setData( 60 );
430 menu
.addAction( i18n( "40%" ) )->setData( 40 );
431 menu
.addAction( i18n( "20%" ) )->setData( 20 );
432 menu
.addAction( i18n( "0%" ) )->setData( 0 );
434 if( EngineController::hasEngineProperty( "HasEqualizer" ) )
437 menu
.addAction( KIcon( "equalizer" ), i18n( "&Equalizer" ), kapp
, SLOT( slotConfigEqualizer() ) )
441 QAction
* a
= menu
.exec( mapToGlobal( e
->pos() ) );
443 const int n
= a
->data().toInt();
446 QSlider::setValue( n
);
447 emit
sliderReleased( n
);
453 Amarok::VolumeSlider::slideEvent( QMouseEvent
*e
)
455 QSlider::setValue( QStyle::sliderValueFromPosition( minimum(), maximum(), e
->pos().x(), width()-2 ) );
459 Amarok::VolumeSlider::wheelEvent( QWheelEvent
*e
)
461 const uint step
= e
->delta() / Amarok::VOLUME_SENSITIVITY
;
462 QSlider::setValue( QSlider::value() + step
);
464 emit
sliderReleased( value() );
468 Amarok::VolumeSlider::paintEvent( QPaintEvent
* )
472 const int padding
= 7;
473 const int offset
= int( double( ( width() - 2 * padding
) * value() ) / maximum() );
475 const QRectF
boundsG( 0, 0, offset
+ padding
, m_pixmapGradient
.height() );
476 p
.drawPixmap( boundsG
, m_pixmapGradient
, boundsG
);
478 const QRectF
boundsI( 0, 0, m_pixmapInset
.width(), m_pixmapInset
.height() );
479 p
.drawPixmap( boundsI
, m_pixmapInset
, boundsI
);
481 const QRectF
targetBounds( offset
- m_handlePixmaps
[0].width() / 2 + padding
, 0, m_handlePixmaps
[m_animCount
].width(), m_handlePixmaps
[m_animCount
].height() );
482 const QRectF
srcBounds( 0, 0, m_handlePixmaps
[m_animCount
].width(), m_handlePixmaps
[m_animCount
].height() );
483 p
.drawPixmap( targetBounds
, m_handlePixmaps
[m_animCount
], srcBounds
);
485 // Draw percentage number
486 p
.setPen( palette().color( QPalette::Disabled
, QColorGroup::Text
).dark() );
488 font
.setPixelSize( 9 );
490 const QRect
rect( 0, 0, 34, 15 );
491 p
.drawText( rect
, Qt::AlignRight
| Qt::AlignVCenter
, QString::number( value() ) + '%' );
495 Amarok::VolumeSlider::enterEvent( QEvent
* )
500 m_animTimer
->start( ANIM_INTERVAL
);
504 Amarok::VolumeSlider::leaveEvent( QEvent
* )
506 // This can happen if you enter and leave the widget quickly
507 if ( m_animCount
== 0 )
511 m_animTimer
->start( ANIM_INTERVAL
);
515 Amarok::VolumeSlider::paletteChange( const QPalette
& )
520 #include "sliderwidget.moc"