Files
cantata/widgets/timeslider.cpp
2013-08-02 19:27:22 +00:00

273 lines
6.7 KiB
C++

/*
* 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 "timeslider.h"
#include "song.h"
#include "settings.h"
#include <QLabel>
#include <QGridLayout>
#include <QProxyStyle>
#include <QTimer>
#include <QApplication>
#include <QMouseEvent>
class ProxyStyle : public QProxyStyle
{
public:
ProxyStyle()
: QProxyStyle()
{
setBaseStyle(qApp->style());
}
int styleHint(StyleHint stylehint, const QStyleOption *opt, const QWidget *widget, QStyleHintReturn *returnData) const
{
if (QStyle::SH_Slider_AbsoluteSetButtons==stylehint) {
return Qt::LeftButton|QProxyStyle::styleHint(stylehint, opt, widget, returnData);
} else {
return QProxyStyle::styleHint(stylehint, opt, widget, returnData);
}
}
};
class TimeLabel : public QLabel
{
public:
TimeLabel(QWidget *p, QSlider *s)
: QLabel(p)
, slider(s)
, visible(true)
, pressed(false)
, showRemaining(Settings::self()->showTimeRemaining())
{
setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
setAttribute(Qt::WA_Hover, true);
}
virtual ~TimeLabel() { }
void saveConfig()
{
Settings::self()->saveShowTimeRemaining(showRemaining);
}
void setEnabled(bool e)
{
if (e!=visible) {
visible=e;
QLabel::setEnabled(e);
setStyleSheet(e ? QString() : QLatin1String("QLabel { color : transparent; }"));
}
}
bool event(QEvent *e)
{
switch (e->type()) {
case QEvent::MouseButtonPress:
if (visible && Qt::NoModifier==static_cast<QMouseEvent *>(e)->modifiers() && Qt::LeftButton==static_cast<QMouseEvent *>(e)->button()) {
pressed=true;
}
break;
case QEvent::MouseButtonRelease:
if (visible && pressed) {
showRemaining=!showRemaining;
updateTimes();
}
pressed=false;
break;
case QEvent::HoverEnter:
if (visible) {
QColor col=palette().highlight().color();
setStyleSheet(QString("QLabel { color : rgb(%1, %2, %3); }").arg(col.red()).arg(col.green()).arg(col.blue()));
}
break;
case QEvent::HoverLeave:
if (visible) {
setStyleSheet(QString());
}
default:
break;
}
return QLabel::event(e);
}
void updateTimes()
{
int value=showRemaining ? slider->maximum()-slider->value() : slider->value();
QString prefix=showRemaining && value ? QLatin1String("-") : QString();
setText(prefix+Song::formattedTime(value)+" / "+Song::formattedTime(slider->maximum()));
}
private:
QSlider *slider;
bool visible;
bool pressed;
bool showRemaining;
};
class PosSlider : public QSlider
{
public:
PosSlider(QWidget *p)
: QSlider(p)
{
setPageStep(0);
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
// Set minimum height to help with some Gtk themes.
// BUG:179
setMinimumHeight(24);
setFocusPolicy(Qt::NoFocus);
setStyle(new ProxyStyle());
}
virtual ~PosSlider() { }
bool event(QEvent *e)
{
if (QEvent::ToolTip==e->type() && maximum()!=minimum()) {
QHelpEvent *he = dynamic_cast<QHelpEvent *>(e);
if (he) {
qreal pc = (qreal)he->x()/(qreal)width();
setToolTip(Song::formattedTime(maximum()*pc));
}
}
return QSlider::event(e);
}
void setRange(int min, int max)
{
QSlider::setRange(min, max);
setValue(min);
if (min==max) {
setToolTip(QString());
}
}
};
TimeSlider::TimeSlider(QWidget *p)
: QWidget(p)
, timer(0)
, lastVal(0)
{
slider=new PosSlider(this);
label=new TimeLabel(this, slider);
label->setAlignment((Qt::RightToLeft==layoutDirection() ? Qt::AlignRight : Qt::AlignLeft)|Qt::AlignVCenter);
QGridLayout *layout=new QGridLayout(this);
layout->setSpacing(0);
layout->setMargin(0);
layout->addWidget(label, 0, 0, 1, 1);
layout->addWidget(slider, 1, 0, 1, 2);
connect(slider, SIGNAL(sliderPressed()), this, SLOT(pressed()));
connect(slider, SIGNAL(sliderReleased()), this, SLOT(released()));
connect(slider, SIGNAL(valueChanged(int)), this, SLOT(updateTimes()));
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
clearTimes();
}
void TimeSlider::startTimer()
{
if (!timer) {
timer=new QTimer(this);
timer->setInterval(1000);
connect(timer, SIGNAL(timeout()), this, SLOT(updatePos()));
}
startTime.restart();
lastVal=value();
timer->start();
}
void TimeSlider::stopTimer()
{
if (timer) {
timer->stop();
}
}
void TimeSlider::setValue(int v)
{
startTime.restart();
lastVal=v;
slider->setValue(v);
updateTimes();
}
void TimeSlider::setRange(int min, int max)
{
slider->setRange(min, max);
label->setEnabled(min!=max);
updateTimes();
}
void TimeSlider::clearTimes()
{
stopTimer();
lastVal=0;
slider->setRange(0, 0);
label->setEnabled(false);
label->updateTimes();
}
void TimeSlider::setOrientation(Qt::Orientation o)
{
slider->setOrientation(o);
}
int TimeSlider::value() const
{
return slider->value();
}
void TimeSlider::saveConfig()
{
label->saveConfig();
}
void TimeSlider::updateTimes()
{
if (slider->value()<172800 && slider->value() != slider->maximum()) {
label->updateTimes();
}
}
void TimeSlider::updatePos()
{
int elapsed=(startTime.elapsed()/1000.0)+0.5;
slider->setValue(lastVal+elapsed);
}
void TimeSlider::pressed()
{
if (timer) {
timer->stop();
}
}
void TimeSlider::released()
{
if (timer) {
timer->start();
}
emit sliderReleased();
}