Custom volume control

This commit is contained in:
craig.p.drummond
2013-10-15 17:19:20 +00:00
committed by craig.p.drummond
parent 797bac910f
commit 42931e1066
10 changed files with 405 additions and 241 deletions

View File

@@ -210,7 +210,7 @@ set(CANTATA_SRCS gui/application.cpp gui/main.cpp gui/initialsettingswizard.cpp
dynamic/dynamic.cpp dynamic/dynamicpage.cpp dynamic/dynamicproxymodel.cpp dynamic/dynamicruledialog.cpp dynamic/dynamicrulesdialog.cpp
widgets/treeview.cpp widgets/listview.cpp widgets/itemview.cpp widgets/autohidingsplitter.cpp widgets/timeslider.cpp
widgets/actionlabel.cpp widgets/playqueueview.cpp widgets/groupedview.cpp widgets/actionitemdelegate.cpp widgets/textbrowser.cpp
widgets/coverwidget.cpp widgets/volumecontrol.cpp widgets/icons.cpp widgets/genrecombo.cpp widgets/toolbar.cpp widgets/menubutton.cpp
widgets/coverwidget.cpp widgets/volumeslider.cpp widgets/icons.cpp widgets/genrecombo.cpp widgets/toolbar.cpp widgets/menubutton.cpp
widgets/toolbutton.cpp widgets/wizardpage.cpp widgets/statuslabel.cpp widgets/searchwidget.cpp widgets/messageoverlay.cpp
widgets/basicitemdelegate.cpp widgets/sizegrip.cpp widgets/sizewidget.cpp widgets/servicestatuslabel.cpp widgets/spacerwidget.cpp
network/networkaccessmanager.cpp network/networkproxyfactory.cpp
@@ -233,7 +233,7 @@ set(CANTATA_MOC_HDRS
mpd/mpdconnection.h mpd/mpdstats.h mpd/mpdstatus.h
dynamic/dynamic.h dynamic/dynamicpage.h dynamic/dynamicruledialog.h dynamic/dynamicrulesdialog.h
widgets/treeview.h widgets/listview.h widgets/itemview.h widgets/autohidingsplitter.h widgets/timeslider.h widgets/actionlabel.h
widgets/playqueueview.h widgets/groupedview.h widgets/actionitemdelegate.h widgets/coverwidget.h widgets/volumecontrol.h
widgets/playqueueview.h widgets/groupedview.h widgets/actionitemdelegate.h widgets/coverwidget.h widgets/volumeslider.h
widgets/genrecombo.h widgets/toolbar.h widgets/searchwidget.h widgets/messageoverlay.h
network/networkaccessmanager.h
context/togglelist.h context/ultimatelyrics.h context/ultimatelyricsprovider.h context/lyricsdialog.h

View File

@@ -62,7 +62,7 @@
rather than waiting for then to be displayed. Again, no UI for this, and
see README for details.
32. Slimmer toolbar - song times are now at the ends of the time slider.
33. Custom time slider.
33. Custom time slider and volume control.
34. Prompt before clearing playqueue.
35. Only show config pages, and tabs, that are relevant to the enabled views.
36. Show action short-cuts in tooltips.

2
README
View File

@@ -389,7 +389,7 @@ streams.xml.gz with:
</streams>
streams.xml.gz & icon.svg need to be placed into a gzip'ed tarball named
Wicked Radio.streams
Wicked Radio.streams.
With the above example, Cantata would list the following in the streams view:

View File

@@ -122,7 +122,7 @@
#include "groupedview.h"
#include "actionitemdelegate.h"
#include "icons.h"
#include "volumecontrol.h"
#include "volumeslider.h"
#include "action.h"
#include "actioncollection.h"
#include "stdactions.h"
@@ -146,39 +146,6 @@ bool DeleteKeyEventHandler::eventFilter(QObject *obj, QEvent *event)
return QObject::eventFilter(obj, event);
}
bool VolumeSliderEventHandler::eventFilter(QObject *obj, QEvent *event)
{
if (QEvent::Wheel==event->type() && (!MPDConnection::self()->isMuted() || !qstrcmp("VolumeControl", obj->metaObject()->className()))) {
int numDegrees = static_cast<QWheelEvent *>(event)->delta() / 8;
int numSteps = numDegrees / 15;
if (numSteps > 0) {
for (int i = 0; i < numSteps; ++i) {
StdActions::self()->increaseVolumeAction->trigger();
}
} else {
for (int i = 0; i > numSteps; --i) {
StdActions::self()->decreaseVolumeAction->trigger();
}
}
return true;
}
return QObject::eventFilter(obj, event);
}
bool VolumeButtonEventHandler::eventFilter(QObject *obj, QEvent *event)
{
if (QEvent::MouseButtonPress==event->type() && Qt::MiddleButton==static_cast<QMouseEvent *>(event)->buttons()) {
down=true;
} else if (QEvent::MouseButtonRelease==event->type()) {
if (down) {
window->muteAction->trigger();
}
down=false;
}
return VolumeSliderEventHandler::eventFilter(obj, event);
}
static int nextKey(int &key) {
int k=key;
@@ -288,7 +255,6 @@ MainWindow::MainWindow(QWidget *parent)
connectionsAction = ActionCollection::get()->createAction("connections", i18n("Collection"), "network-server");
outputsAction = ActionCollection::get()->createAction("outputs", i18n("Outputs"), Icons::self()->speakerIcon);
stopAfterTrackAction = ActionCollection::get()->createAction("stopaftertrack", i18n("Stop After Track"), Icons::self()->toolbarStopIcon);
muteAction = ActionCollection::get()->createAction("mute", i18n("Mute"));
addPlayQueueToStoredPlaylistAction = ActionCollection::get()->createAction("addpqtostoredplaylist", i18n("Add To Stored Playlist"), Icons::self()->playlistIcon);
removeFromPlayQueueAction = ActionCollection::get()->createAction("removefromplaylist", i18n("Remove From Play Queue"), "list-remove");
copyTrackInfoAction = ActionCollection::get()->createAction("copytrackinfo", i18n("Copy Track Info"));
@@ -342,19 +308,14 @@ MainWindow::MainWindow(QWidget *parent)
updateNextTrack(-1);
StdActions::self()->prevTrackAction->setEnabled(false);
enableStopActions(false);
volumeSlider->initActions();
addAction(StdActions::self()->increaseVolumeAction);
addAction(StdActions::self()->decreaseVolumeAction);
addAction(muteAction);
#if defined ENABLE_KDE_SUPPORT
StdActions::self()->prevTrackAction->setGlobalShortcut(KShortcut(Qt::Key_MediaPrevious));
StdActions::self()->nextTrackAction->setGlobalShortcut(KShortcut(Qt::Key_MediaNext));
StdActions::self()->playPauseTrackAction->setGlobalShortcut(KShortcut(Qt::Key_MediaPlay));
StdActions::self()->stopPlaybackAction->setGlobalShortcut(KShortcut(Qt::Key_MediaStop));
StdActions::self()->stopAfterCurrentTrackAction->setGlobalShortcut(KShortcut());
StdActions::self()->increaseVolumeAction->setGlobalShortcut(KShortcut(Qt::Key_VolumeUp));
StdActions::self()->decreaseVolumeAction->setGlobalShortcut(KShortcut(Qt::Key_VolumeDown));
muteAction->setGlobalShortcut(KShortcut(Qt::Key_VolumeMute));
#endif
copyTrackInfoAction->setShortcut(QKeySequence::Copy);
@@ -374,13 +335,6 @@ MainWindow::MainWindow(QWidget *parent)
devicesTabAction->setShortcut(Qt::AltModifier+nextKey(pageKey));
#endif // ENABLE_DEVICES_SUPPORT
volumeSliderEventHandler = new VolumeSliderEventHandler(this);
volumeControl = new VolumeControl(volumeButton);
volumeControl->installEventFilter(volumeSliderEventHandler);
volumeControl->installSliderEventFilter(volumeSliderEventHandler);
volumeButton->installEventFilter(new VolumeButtonEventHandler(this));
volumeButton->setMenu(volumeControl);
connectionsAction->setMenu(new QMenu(this));
connectionsGroup=new QActionGroup(connectionsAction->menu());
outputsAction->setMenu(new QMenu(this));
@@ -388,7 +342,6 @@ MainWindow::MainWindow(QWidget *parent)
addPlayQueueToStoredPlaylistAction->setMenu(PlaylistsModel::self()->menu());
menuButton->setMenu(mainMenu);
volumeButton->setIcon(Icons::self()->toolbarVolumeHighIcon);
playPauseTrackButton->setDefaultAction(StdActions::self()->playPauseTrackAction);
stopTrackButton->setDefaultAction(StdActions::self()->stopPlaybackAction);
@@ -501,7 +454,7 @@ MainWindow::MainWindow(QWidget *parent)
QList<QToolButton *> playbackBtns;
QList<QToolButton *> controlBtns;
playbackBtns << prevTrackButton << stopTrackButton << playPauseTrackButton << nextTrackButton;
controlBtns << volumeButton << menuButton << songInfoButton;
controlBtns << menuButton << songInfoButton;
int playbackIconSize=28;
int controlIconSize=22;
@@ -761,11 +714,7 @@ MainWindow::MainWindow(QWidget *parent)
connect(StdActions::self()->stopPlaybackAction, SIGNAL(triggered(bool)), this, SLOT(stopPlayback()));
connect(StdActions::self()->stopAfterCurrentTrackAction, SIGNAL(triggered(bool)), this, SLOT(stopAfterCurrentTrack()));
connect(stopAfterTrackAction, SIGNAL(triggered(bool)), this, SLOT(stopAfterTrack()));
connect(volumeControl, SIGNAL(valueChanged(int)), MPDConnection::self(), SLOT(setVolume(int)));
connect(this, SIGNAL(setVolume(int)), MPDConnection::self(), SLOT(setVolume(int)));
connect(StdActions::self()->increaseVolumeAction, SIGNAL(triggered(bool)), volumeControl, SLOT(increaseVolume()));
connect(StdActions::self()->decreaseVolumeAction, SIGNAL(triggered(bool)), volumeControl, SLOT(decreaseVolume()));
connect(muteAction, SIGNAL(triggered(bool)), MPDConnection::self(), SLOT(toggleMute()));
connect(positionSlider, SIGNAL(sliderReleased()), this, SLOT(setPosition()));
connect(randomPlayQueueAction, SIGNAL(triggered(bool)), MPDConnection::self(), SLOT(setRandom(bool)));
connect(repeatPlayQueueAction, SIGNAL(triggered(bool)), MPDConnection::self(), SLOT(setRepeat(bool)));
@@ -1639,13 +1588,13 @@ void MainWindow::startVolumeFade()
}
stopState=StopState_Stopping;
volumeSlider->setFadingStop(true);
if (!volumeFade) {
volumeFade = new QPropertyAnimation(this, "volume");
volumeFade->setDuration(Settings::self()->stopFadeDuration());
}
origVolume=volume;
lastVolume=volume;
volumeFade->setStartValue(volume);
origVolume=lastVolume=volumeSlider->value();
volumeFade->setStartValue(origVolume);
volumeFade->setEndValue(-1);
volumeFade->start();
}
@@ -1659,11 +1608,16 @@ void MainWindow::stopVolumeFade()
}
}
int MainWindow::mpdVolume() const
{
return volumeSlider->value();
}
void MainWindow::setMpdVolume(int v)
{
if (-1==v) {
volume=origVolume;
emit setVolume(origVolume);
volumeSlider->setFadingStop(false);
emit setVolume(volumeSlider->value());
if (StopState_Stopping==stopState) {
emit stop();
}
@@ -1942,44 +1896,6 @@ void MainWindow::updateStatus(MPDStatus * const status)
}
}
if (!stopState) {
volume=status->volume();
if (volume<=0) {
volumeButton->setIcon(Icons::self()->toolbarVolumeMutedIcon);
} else if (volume<=33) {
volumeButton->setIcon(Icons::self()->toolbarVolumeLowIcon);
} else if (volume<=67) {
volumeButton->setIcon(Icons::self()->toolbarVolumeMediumIcon);
} else {
volumeButton->setIcon(Icons::self()->toolbarVolumeHighIcon);
}
volumeControl->blockSignals(true);
if (volume<0) {
volumeButton->setEnabled(false);
volumeButton->setToolTip(i18n("Volume Disabled"));
volumeControl->setToolTip(i18n("Volume Disabled"));
volumeControl->setValue(0);
} else {
int unmuteVolume=-1;
if (0==volume) {
unmuteVolume=MPDConnection::self()->unmuteVolume();
if (unmuteVolume>0) {
volume=unmuteVolume;
}
}
volumeButton->setEnabled(true);
volumeButton->setToolTip(unmuteVolume>0 ? i18n("Volume %1% (Muted)", volume) : i18n("Volume %1%", volume));
volumeControl->setToolTip(volumeButton->toolTip());
volumeControl->setValue(volume);
}
muteAction->setEnabled(volumeButton->isEnabled());
StdActions::self()->increaseVolumeAction->setEnabled(volumeButton->isEnabled());
StdActions::self()->decreaseVolumeAction->setEnabled(volumeButton->isEnabled());
volumeControl->blockSignals(false);
}
randomPlayQueueAction->setChecked(status->random());
repeatPlayQueueAction->setChecked(status->repeat());
singlePlayQueueAction->setChecked(status->single());
@@ -2774,7 +2690,7 @@ void MainWindow::showSearch()
bool MainWindow::fadeWhenStop() const
{
return fadeStop && volumeButton->isEnabled();
return fadeStop && volumeSlider->isEnabled();
}
void MainWindow::expandAll()

View File

@@ -75,7 +75,6 @@ class QTimer;
class QPropertyAnimation;
class QActionGroup;
class QDateTime;
class VolumeControl;
class TrayItem;
class GtkProxyStyle;
@@ -104,26 +103,6 @@ private:
QAction *act;
};
class VolumeSliderEventHandler : public QObject
{
public:
VolumeSliderEventHandler(MainWindow *w) : QObject((QObject *)w), window(w) { }
protected:
bool eventFilter(QObject *obj, QEvent *event);
protected:
MainWindow * const window;
};
class VolumeButtonEventHandler : public VolumeSliderEventHandler
{
public:
VolumeButtonEventHandler(MainWindow *w) : VolumeSliderEventHandler(w), down(false) { }
protected:
bool eventFilter(QObject *obj, QEvent *event);
private:
bool down;
};
#ifdef ENABLE_KDE_SUPPORT
class MainWindow : public KXmlGuiWindow, private Ui::MainWindow
#else
@@ -154,7 +133,7 @@ public:
MainWindow(QWidget *parent = 0);
~MainWindow();
int mpdVolume() const { return volume; }
int mpdVolume() const;
int currentTrackPosition() const;
QString coverFile() const;
@@ -200,7 +179,7 @@ public Q_SLOTS:
void configureShortcuts();
void saveShortcuts();
#endif
void setMpdVolume(int );
void setMpdVolume(int v);
void songLoaded();
void messageWidgetVisibility(bool v);
void mpdConnectionStateChanged(bool connected);
@@ -319,8 +298,6 @@ private:
PlayQueueModel playQueueModel;
PlayQueueProxyModel playQueueProxyModel;
bool autoScrollPlayQueue;
VolumeSliderEventHandler *volumeSliderEventHandler;
VolumeControl *volumeControl;
Action *prefAction;
#ifdef ENABLE_KDE_SUPPORT
Action *shortcutsAction;
@@ -330,7 +307,6 @@ private:
Action *outputsAction;
QActionGroup *connectionsGroup;
Action *stopAfterTrackAction;
Action *muteAction;
Action *removeFromPlayQueueAction;
Action *addPlayQueueToStoredPlaylistAction;
Action *promptClearPlayQueueAction;
@@ -430,9 +406,6 @@ private:
QMediaPlayer *httpStream;
#endif
#endif
friend class VolumeSliderEventHandler;
friend class VolumeButtonEventHandler;
friend class CoverEventHandler;
friend class TrayItem;
};

View File

@@ -108,10 +108,26 @@
<number>0</number>
</property>
<item>
<widget class="ToolButton" name="songInfoButton"/>
<widget class="VolumeSlider" name="volumeSlider"/>
</item>
<item>
<widget class="ToolButton" name="volumeButton"/>
<spacer name="volumeSliderSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>4</width>
<height>4</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="ToolButton" name="songInfoButton"/>
</item>
<item>
<widget class="MenuButton" name="menuButton"/>
@@ -429,6 +445,11 @@
<extends>QWidget</extends>
<header>sizegrip.h</header>
</customwidget>
<customwidget>
<class>VolumeSlider</class>
<extends>QSlider</extends>
<header>volumeslider.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>

View File

@@ -37,6 +37,32 @@
#include "song.h"
#include "stdactions.h"
class VolumeSliderEventHandler : public QObject
{
public:
VolumeSliderEventHandler(QObject *p) : QObject(p) { }
protected:
bool eventFilter(QObject *obj, QEvent *event)
{
if (QEvent::Wheel==event->type()) {
int numDegrees = static_cast<QWheelEvent *>(event)->delta() / 8;
int numSteps = numDegrees / 15;
if (numSteps > 0) {
for (int i = 0; i < numSteps; ++i) {
StdActions::self()->increaseVolumeAction->trigger();
}
} else {
for (int i = 0; i > numSteps; --i) {
StdActions::self()->decreaseVolumeAction->trigger();
}
}
return true;
}
return QObject::eventFilter(obj, event);
}
};
TrayItem::TrayItem(MainWindow *p)
: QObject(p)
, mw(p)
@@ -93,7 +119,7 @@ void TrayItem::setup()
}
trayItem = new QSystemTrayIcon(this);
trayItem->installEventFilter(mw->volumeSliderEventHandler);
trayItem->installEventFilter(new VolumeSliderEventHandler(this));
trayItemMenu = new QMenu(0);
trayItemMenu->addAction(StdActions::self()->prevTrackAction);
trayItemMenu->addAction(StdActions::self()->playPauseTrackAction);

View File

@@ -1,91 +0,0 @@
/*
* Cantata
*
* Copyright (c) 2011-2013 Craig Drummond <craig.p.drummond@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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "volumecontrol.h"
#include "icon.h"
#include <QFrame>
#include <QSlider>
#include <QLabel>
#include <QVBoxLayout>
#include <QApplication>
VolumeControl::VolumeControl(QWidget *parent)
: QMenu(parent)
{
QFrame *w = new QFrame(this);
slider = new QSlider(w);
QLabel *increase = new QLabel(QLatin1String("+"), w);
QLabel *decrease = new QLabel(QLatin1String("-"), w);
increase->setAlignment(Qt::AlignHCenter);
decrease->setAlignment(Qt::AlignHCenter);
QVBoxLayout *l = new QVBoxLayout(w);
l->setMargin(3);
l->setSpacing(0);
l->addWidget(increase);
l->addWidget(slider);
l->addWidget(decrease);
QHBoxLayout *layout = new QHBoxLayout(this);
layout->setMargin(0);
layout->addWidget(w);
connect(slider, SIGNAL(valueChanged(int)), SIGNAL(valueChanged(int)));
int size=Icon::stdSize(QApplication::fontMetrics().height());
slider->setMinimumHeight(size*12);
slider->setMaximumHeight(size*12);
slider->setMinimumWidth(size*1.5);
slider->setMaximumWidth(size*1.5);
slider->setOrientation(Qt::Vertical);
slider->setMinimum(0);
slider->setMaximum(100);
slider->setPageStep(5);
adjustSize();
}
VolumeControl::~VolumeControl()
{
}
void VolumeControl::installSliderEventFilter(QObject *filter)
{
slider->installEventFilter(filter);
}
void VolumeControl::increaseVolume()
{
slider->triggerAction(QAbstractSlider::SliderPageStepAdd);
}
void VolumeControl::decreaseVolume()
{
slider->triggerAction(QAbstractSlider::SliderPageStepSub);
}
void VolumeControl::setValue(int v)
{
slider->setValue(v);
}

302
widgets/volumeslider.cpp Normal file
View File

@@ -0,0 +1,302 @@
/*
* Cantata
*
* Copyright (c) 2011-2013 Craig Drummond <craig.p.drummond@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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "volumeslider.h"
#include "localize.h"
#include "mpdconnection.h"
#include "mpdstatus.h"
#include "action.h"
#include "actioncollection.h"
#include "stdactions.h"
#include <QStyle>
#include <QPainter>
#include <QPainterPath>
#include <QProxyStyle>
#include <QApplication>
#include <QLabel>
#include <QMouseEvent>
#include <QMenu>
#ifdef ENABLE_KDE_SUPPORT
#include <KDE/KShortcut>
#endif
class ProxyStyle : public QProxyStyle
{
public:
ProxyStyle()
: QProxyStyle()
{
setBaseStyle(qApp->style());
}
int styleHint(StyleHint stylehint, const QStyleOption *opt, const QWidget *widget, QStyleHintReturn *returnData) const
{
if (SH_Slider_AbsoluteSetButtons==stylehint) {
return Qt::LeftButton|QProxyStyle::styleHint(stylehint, opt, widget, returnData);
} else {
return QProxyStyle::styleHint(stylehint, opt, widget, returnData);
}
}
};
static const int constWidthStep=4;
static const int constHeightStep=2;
static QColor clampColor(const QColor &col)
{
static const int constMin=64;
static const int constMax=196;
if (col.value()<constMin) {
return QColor(constMin, constMin, constMin);
} else if (col.value()>constMax) {
return QColor(constMax, constMax, constMax);
}
return col;
}
VolumeSlider::VolumeSlider(QWidget *p)
: QSlider(p)
, lineWidth(0)
, shown(false)
, down(false)
, fadingStop(false)
, muteAction(0)
, menu(0)
{
int fontHeight=fontMetrics().height();
setRange(0, 100);
setPageStep(5);
lineWidth=fontHeight>22 ? 2 : 1;
int w=lineWidth*constWidthStep*19;
int h=lineWidth*constHeightStep*10;
setFixedHeight(h+1);
setFixedWidth(w);
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
setOrientation(Qt::Horizontal);
setStyle(new ProxyStyle());
setStyleSheet(QString("QSlider::groove:horizontal {border: 0px;} "
"QSlider::sub-page:horizontal {border: 0px;} "
"QSlider::handle:horizontal {width: 1px; height:%1px; margin:0;}").arg(h));
textCol=clampColor(palette().color(QPalette::Active, QPalette::Text));
pixmaps[0]=pixmaps[1]=0;
generatePixmaps();
}
void VolumeSlider::initActions()
{
if (muteAction) {
return;
}
muteAction = ActionCollection::get()->createAction("mute", i18n("Mute"));
addAction(muteAction);
#ifdef ENABLE_KDE_SUPPORT
muteAction->setGlobalShortcut(KShortcut(Qt::Key_VolumeMute));
StdActions::self()->increaseVolumeAction->setGlobalShortcut(KShortcut(Qt::Key_VolumeUp));
StdActions::self()->decreaseVolumeAction->setGlobalShortcut(KShortcut(Qt::Key_VolumeDown));
#endif
connect(muteAction, SIGNAL(triggered(bool)), MPDConnection::self(), SLOT(toggleMute()));
connect(MPDStatus::self(), SIGNAL(updated()), this, SLOT(updateMpdStatus()));
connect(StdActions::self()->increaseVolumeAction, SIGNAL(triggered(bool)), this, SLOT(increaseVolume()));
connect(StdActions::self()->decreaseVolumeAction, SIGNAL(triggered(bool)), this, SLOT(decreaseVolume()));
connect(this, SIGNAL(valueChanged(int)), MPDConnection::self(), SLOT(setVolume(int)));
}
void VolumeSlider::showEvent(QShowEvent *e)
{
if (!shown) {
shown=true;
QLabel lbl(parentWidget());
lbl.ensurePolished();
QColor col=clampColor(lbl.palette().text().color());
if (col!=textCol) {
textCol=col;
generatePixmaps();
}
}
QSlider::showEvent(e);
}
void VolumeSlider::paintEvent(QPaintEvent *)
{
bool reverse=Qt::RightToLeft==layoutDirection();
QPainter p(this);
bool muted=MPDConnection::self()->isMuted();
if (muted) {
p.setOpacity(0.25);
}
int steps=(value()/10.0)+0.5;
p.drawPixmap(0, 0, *(pixmaps[0]));
if (steps>0) {
if (steps<10) {
p.setClipRect(reverse
? QRect(width()-((steps*constWidthStep*2)-constWidthStep), 0, width(), height())
: QRect(0, 0, (steps*constWidthStep*2)-constWidthStep, height()));
p.setClipping(true);
}
p.drawPixmap(0, 0, *(pixmaps[1]));
if (steps<10) {
p.setClipping(false);
}
}
if (muted) {
p.setOpacity(1.0);
}
p.setPen(textCol);
QFont f(font());
f.setPixelSize(height()/2.0);
p.setFont(f);
if (muted) {
QFontMetrics fm(p.fontMetrics());
QString text(fm.elidedText(i18n("Muted"), reverse ? Qt::ElideLeft : Qt::ElideRight, width(), QPalette::WindowText));
p.drawText(rect(), Qt::AlignLeft, text);
} else {
p.drawText(rect(), Qt::AlignLeft, QString("%1%").arg(value()));
}
}
void VolumeSlider::mousePressEvent(QMouseEvent *ev)
{
if (Qt::MiddleButton==ev->buttons()) {
down=true;
} else {
QSlider::mousePressEvent(ev);
}
}
void VolumeSlider::mouseReleaseEvent(QMouseEvent *ev)
{
if (down) {
down=false;
muteAction->trigger();
update();
} else {
QSlider::mouseReleaseEvent(ev);
}
}
void VolumeSlider::contextMenuEvent(QContextMenuEvent *ev)
{
static const char *constValProp="val";
if (!menu) {
menu=new QMenu(this);
menu->setTitle(i18n("Volume"));
muteMenuAction=menu->addAction(i18n("Mute"));
muteMenuAction->setProperty(constValProp, -1);
for (int i=0; i<11; ++i) {
menu->addAction(QString("%1%").arg(i*10))->setProperty(constValProp, i*10);
}
}
muteMenuAction->setText(MPDConnection::self()->isMuted() ? i18n("Unmute") : i18n("Mute"));
QAction *ret = menu->exec(mapToGlobal(ev->pos()));
if (ret) {
int val=ret->property(constValProp).toInt();
if (-1==val) {
muteAction->trigger();
} else {
setValue(val);
}
}
}
void VolumeSlider::updateMpdStatus()
{
if (fadingStop) {
return;
}
int volume=MPDStatus::self()->volume();
blockSignals(true);
if (volume<0) {
setEnabled(false);
setToolTip(i18n("Volume Disabled"));
setValue(0);
} else {
int unmuteVolume=-1;
if (0==volume) {
unmuteVolume=MPDConnection::self()->unmuteVolume();
if (unmuteVolume>0) {
volume=unmuteVolume;
}
}
setEnabled(true);
setToolTip(unmuteVolume>0 ? i18n("Volume %1% (Muted)", volume) : i18n("Volume %1%", volume));
setValue(volume);
}
update();
muteAction->setEnabled(isEnabled());
StdActions::self()->increaseVolumeAction->setEnabled(isEnabled());
StdActions::self()->decreaseVolumeAction->setEnabled(isEnabled());
blockSignals(false);
}
void VolumeSlider::increaseVolume()
{
triggerAction(QAbstractSlider::SliderPageStepAdd);
}
void VolumeSlider::decreaseVolume()
{
triggerAction(QAbstractSlider::SliderPageStepSub);
}
void VolumeSlider::generatePixmaps()
{
if (pixmaps[0]) {
delete pixmaps[0];
}
if (pixmaps[1]) {
delete pixmaps[1];
}
pixmaps[0]=generatePixmap(false);
pixmaps[1]=generatePixmap(true);
}
QPixmap * VolumeSlider::generatePixmap(bool filled)
{
bool reverse=Qt::RightToLeft==layoutDirection();
QPixmap *pix=new QPixmap(size());
pix->fill(Qt::transparent);
QPainter p(pix);
p.setPen(textCol);
for (int i=0; i<10; ++i) {
int barHeight=(lineWidth*constHeightStep)*(i+1);
QRect r(reverse ? pix->width()-(constWidthStep+(i*lineWidth*constWidthStep*2))
: i*lineWidth*constWidthStep*2,
pix->height()-(barHeight+1), (lineWidth*constWidthStep)-1, barHeight);
if (filled) {
p.fillRect(r, textCol);
} else {
p.drawRect(r);
}
}
return pix;
}

View File

@@ -21,35 +21,52 @@
* Boston, MA 02110-1301, USA.
*/
#ifndef VOLUMECONTROL_H
#define VOLUMECONTROL_H
#ifndef VOLUMESLIDER_H
#define VOLUMESLIDER_H
#include <QMenu>
#include <QSlider>
#include <QColor>
class QSlider;
class QPixmap;
class QMenu;
class Action;
class QAction;
class VolumeControl : public QMenu
class VolumeSlider : public QSlider
{
Q_OBJECT
public:
VolumeControl(QWidget *parent);
virtual ~VolumeControl();
VolumeSlider(QWidget *p=0);
virtual ~VolumeSlider() { }
void installSliderEventFilter(QObject *filter);
void initActions();
void setFadingStop(bool f) { fadingStop=f; }
void showEvent(QShowEvent *e);
void paintEvent(QPaintEvent *ev);
void mousePressEvent(QMouseEvent *ev);
void mouseReleaseEvent(QMouseEvent *ev);
void contextMenuEvent(QContextMenuEvent *ev);
public Q_SLOTS:
private Q_SLOTS:
void updateMpdStatus();
void increaseVolume();
void decreaseVolume();
void setValue(int v);
QSlider * sliderWidget() { return slider; }
Q_SIGNALS:
void valueChanged(int v);
private:
QSlider *slider;
void generatePixmaps();
QPixmap * generatePixmap(bool filled);
private:
int lineWidth;
bool shown;
bool down;
bool fadingStop;
QColor textCol;
QPixmap *pixmaps[2];
Action *muteAction;
QAction *muteMenuAction;
QMenu *menu;
};
#endif