mirror of
https://github.com/clementine-player/Clementine
synced 2024-12-17 03:45:56 +01:00
370 lines
10 KiB
C++
370 lines
10 KiB
C++
/***************************************************************************
|
|
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 <QApplication>
|
|
#include <QBitmap>
|
|
#include <QBrush>
|
|
#include <QImage>
|
|
#include <QPainter>
|
|
#include <QSize>
|
|
#include <QTimer>
|
|
#include <QStyle>
|
|
#include <QMenu>
|
|
#include <QWheelEvent>
|
|
#include <QMouseEvent>
|
|
#include <QStyleOptionSlider>
|
|
|
|
|
|
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<QAction*, int> 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();
|
|
}
|