strawberry-audio-player-win.../src/widgets/volumeslider.cpp

285 lines
8.2 KiB
C++
Raw Normal View History

2018-02-27 18:06:05 +01:00
/***************************************************************************
volumeslider.cpp
-------------------
2018-02-27 18:06:05 +01:00
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
copyright : (C) 2018-2023 by Jonas Kvinge
email : jonas@jkvinge.net
2018-02-27 18:06:05 +01:00
***************************************************************************/
/***************************************************************************
* *
* 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 <QSlider>
2021-06-20 19:04:08 +02:00
#include <QHash>
#include <QString>
2018-02-27 18:06:05 +01:00
#include <QImage>
#include <QPixmap>
#include <QPalette>
2018-02-27 18:06:05 +01:00
#include <QPainter>
#include <QPainterPath>
#include <QFont>
#include <QBrush>
#include <QPen>
#include <QPoint>
#include <QPolygon>
#include <QRect>
2018-02-27 18:06:05 +01:00
#include <QMenu>
#include <QStyle>
#include <QStyleOption>
#include <QTimer>
#include <QAction>
#include <QLinearGradient>
#include <QStyleOptionViewItem>
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
# include <QEnterEvent>
#else
# include <QEvent>
2018-02-27 18:06:05 +01:00
#endif
#include <QPaintEvent>
#include <QContextMenuEvent>
#include <QMouseEvent>
#include <QWheelEvent>
2018-02-27 18:06:05 +01:00
#include "volumeslider.h"
2018-02-27 18:06:05 +01:00
2021-06-12 16:06:30 +02:00
VolumeSlider::VolumeSlider(QWidget *parent, const uint max)
2021-10-30 02:21:29 +02:00
: SliderSlider(Qt::Horizontal, parent, static_cast<int>(max)),
2021-06-20 23:53:28 +02:00
anim_enter_(false),
2021-06-12 16:06:30 +02:00
anim_count_(0),
timer_anim_(new QTimer(this)),
2022-06-13 00:23:42 +02:00
pixmap_inset_(drawVolumePixmap()) {
2021-06-12 16:06:30 +02:00
2018-02-27 18:06:05 +01:00
setFocusPolicy(Qt::NoFocus);
// Store theme colors to check theme change at paintEvent
2021-06-12 16:06:30 +02:00
previous_theme_text_color_ = palette().color(QPalette::WindowText);
previous_theme_highlight_color_ = palette().color(QPalette::Highlight);
2018-02-27 18:06:05 +01:00
drawVolumeSliderHandle();
generateGradient();
2021-06-12 16:06:30 +02:00
setMinimumWidth(pixmap_inset_.width());
setMinimumHeight(pixmap_inset_.height());
2018-02-27 18:06:05 +01:00
2021-06-12 16:06:30 +02:00
QObject::connect(timer_anim_, &QTimer::timeout, this, &VolumeSlider::slotAnimTimer);
2019-03-09 16:48:45 +01:00
2018-02-27 18:06:05 +01:00
}
2019-03-09 16:48:45 +01:00
void VolumeSlider::SetEnabled(const bool enabled) {
QSlider::setEnabled(enabled);
QSlider::setVisible(enabled);
}
void VolumeSlider::paintEvent(QPaintEvent*) {
2018-02-27 18:06:05 +01:00
QPainter p(this);
const int padding = 7;
2021-10-11 22:28:28 +02:00
const int offset = static_cast<int>(static_cast<double>((width() - 2 * padding) * value()) / maximum());
2018-02-27 18:06:05 +01:00
2018-10-02 00:46:54 +02:00
// If theme changed since last paintEvent, redraw the volume pixmap with new theme colors
2021-06-12 16:06:30 +02:00
if (previous_theme_text_color_ != palette().color(QPalette::WindowText)) {
pixmap_inset_ = drawVolumePixmap();
previous_theme_text_color_ = palette().color(QPalette::WindowText);
2018-02-27 18:06:05 +01:00
}
2021-06-12 16:06:30 +02:00
if (previous_theme_highlight_color_ != palette().color(QPalette::Highlight)) {
2018-02-27 18:06:05 +01:00
drawVolumeSliderHandle();
2021-06-12 16:06:30 +02:00
previous_theme_highlight_color_ = palette().color(QPalette::Highlight);
2018-02-27 18:06:05 +01:00
}
2021-06-12 16:06:30 +02:00
p.drawPixmap(0, 0, pixmap_gradient_, 0, 0, offset + padding, 0);
p.drawPixmap(0, 0, pixmap_inset_);
p.drawPixmap(offset - handle_pixmaps_[0].width() / 2 + padding, 0, handle_pixmaps_[anim_count_]);
2018-02-27 18:06:05 +01:00
// Draw percentage number
QStyleOptionViewItem opt;
p.setPen(opt.palette.color(QPalette::Normal, QPalette::Text));
QFont vol_font(opt.font);
vol_font.setPixelSize(9);
p.setFont(vol_font);
const QRect rect(0, 0, 34, 15);
p.drawText(rect, Qt::AlignRight | Qt::AlignVCenter, QString::number(value()) + '%');
2019-03-09 16:48:45 +01:00
2018-02-27 18:06:05 +01:00
}
void VolumeSlider::generateGradient() {
2019-03-09 16:48:45 +01:00
const QImage mask(":/pictures/volumeslider-gradient.png");
2018-02-27 18:06:05 +01:00
QImage gradient_image(mask.size(), QImage::Format_ARGB32_Premultiplied);
QPainter p(&gradient_image);
2019-03-09 16:48:45 +01:00
QLinearGradient gradient(gradient_image.rect().topLeft(), gradient_image.rect().topRight());
gradient.setColorAt(0, palette().color(QPalette::Window));
gradient.setColorAt(1, palette().color(QPalette::Highlight));
p.fillRect(gradient_image.rect(), QBrush(gradient));
2018-02-27 18:06:05 +01:00
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
p.drawImage(0, 0, mask);
p.end();
2019-03-09 16:48:45 +01:00
pixmap_gradient_ = QPixmap::fromImage(gradient_image);
2018-02-27 18:06:05 +01:00
}
void VolumeSlider::slotAnimTimer() {
if (anim_enter_) {
++anim_count_;
update();
if (anim_count_ == ANIM_MAX - 1) timer_anim_->stop();
}
else {
--anim_count_;
update();
if (anim_count_ == 0) timer_anim_->stop();
}
2019-03-09 16:48:45 +01:00
2018-02-27 18:06:05 +01:00
}
2019-03-09 16:48:45 +01:00
void VolumeSlider::paletteChange(const QPalette&) {
2018-02-27 18:06:05 +01:00
generateGradient();
}
2022-03-22 21:09:05 +01:00
QPixmap VolumeSlider::drawVolumePixmap() const {
2019-03-09 16:48:45 +01:00
2018-02-27 18:06:05 +01:00
QPixmap pixmap(112, 36);
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
QPen pen(palette().color(QPalette::WindowText), 0.3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
painter.setPen(pen);
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
painter.setRenderHint(QPainter::Antialiasing);
painter.setRenderHint(QPainter::SmoothPixmapTransform);
// Draw volume control pixmap
QPolygon poly;
2019-03-09 16:48:45 +01:00
poly << QPoint(6, 21) << QPoint(104, 21) << QPoint(104, 7) << QPoint(6, 16) << QPoint(6, 21);
2018-02-27 18:06:05 +01:00
QPainterPath path;
path.addPolygon(poly);
painter.drawPolygon(poly);
painter.drawLine(6, 29, 104, 29);
2021-06-12 16:06:30 +02:00
2018-02-27 18:06:05 +01:00
// Return QPixmap
return pixmap;
2019-03-09 16:48:45 +01:00
2018-02-27 18:06:05 +01:00
}
2019-03-09 16:48:45 +01:00
void VolumeSlider::drawVolumeSliderHandle() {
2018-02-27 18:06:05 +01:00
QImage pixmapHandle(":/pictures/volumeslider-handle.png");
QImage pixmapHandleGlow(":/pictures/volumeslider-handle_glow.png");
QImage pixmapHandleGlow_image(pixmapHandleGlow.size(), QImage::Format_ARGB32_Premultiplied);
QPainter painter(&pixmapHandleGlow_image);
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
painter.setRenderHint(QPainter::Antialiasing);
painter.setRenderHint(QPainter::SmoothPixmapTransform);
2021-06-12 16:06:30 +02:00
// Repaint volume slider handle glow image with theme highlight color
2018-02-27 18:06:05 +01:00
painter.fillRect(pixmapHandleGlow_image.rect(), QBrush(palette().color(QPalette::Highlight)));
painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
painter.drawImage(0, 0, pixmapHandleGlow);
2018-10-02 00:38:52 +02:00
2018-10-02 00:46:54 +02:00
// Overlay the volume slider handle image
2018-02-27 18:06:05 +01:00
painter.setCompositionMode(QPainter::CompositionMode_SourceAtop);
painter.drawImage(0, 0, pixmapHandle);
// BEGIN Calculate handle animation pixmaps for mouse-over effect
2022-02-06 04:19:45 +01:00
float opacity = 0.0F;
const float step = 1.0F / ANIM_MAX;
2018-02-27 18:06:05 +01:00
QImage dst;
2021-06-12 16:06:30 +02:00
handle_pixmaps_.clear();
2018-02-27 18:06:05 +01:00
for (int i = 0; i < ANIM_MAX; ++i) {
dst = pixmapHandle.copy();
QPainter p(&dst);
p.setOpacity(opacity);
p.drawImage(0, 0, pixmapHandleGlow_image);
p.end();
2021-06-12 16:06:30 +02:00
handle_pixmaps_.append(QPixmap::fromImage(dst));
2018-02-27 18:06:05 +01:00
opacity += step;
}
// END
2019-03-09 16:48:45 +01:00
2018-02-27 18:06:05 +01:00
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
void VolumeSlider::enterEvent(QEnterEvent*) {
#else
void VolumeSlider::enterEvent(QEvent*) {
#endif
anim_enter_ = true;
anim_count_ = 0;
timer_anim_->start(ANIM_INTERVAL);
}
void VolumeSlider::leaveEvent(QEvent*) {
// This can happen if you enter and leave the widget quickly
if (anim_count_ == 0) anim_count_ = 1;
anim_enter_ = false;
timer_anim_->start(ANIM_INTERVAL);
}
void VolumeSlider::contextMenuEvent(QContextMenuEvent *e) {
QHash<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 VolumeSlider::slideEvent(QMouseEvent *e) {
QSlider::setValue(QStyle::sliderValueFromPosition(minimum(), maximum(), e->pos().x(), width() - 2));
}
void VolumeSlider::mousePressEvent(QMouseEvent *e) {
if (e->button() != Qt::RightButton) {
SliderSlider::mousePressEvent(e);
slideEvent(e);
}
}
void VolumeSlider::wheelEvent(QWheelEvent *e) {
wheeling_ = true;
const int step = e->angleDelta().y() / (e->angleDelta().x() == 0 ? 30 : -30);
QSlider::setValue(SliderSlider::value() + step);
emit SliderReleased(value());
wheeling_ = false;
}