Add volume controls to the PiP window

Add volume toggle and volume level controls to the PiP window.
This commit is contained in:
Alexander Bushnev 2021-05-07 20:13:45 +02:00 committed by John Preston
parent afc5191644
commit d752aa3481
2 changed files with 164 additions and 21 deletions

View file

@ -948,6 +948,9 @@ Pip::Pip(
}) })
, _playbackProgress(std::make_unique<PlaybackProgress>()) , _playbackProgress(std::make_unique<PlaybackProgress>())
, _rotation(data->owner().mediaRotation().get(data)) , _rotation(data->owner().mediaRotation().get(data))
, _lastPositiveVolume((Core::App().settings().videoVolume() > 0.)
? Core::App().settings().videoVolume()
: Core::Settings::kDefaultVolume)
, _roundRect(ImageRoundRadius::Large, st::radialBg) , _roundRect(ImageRoundRadius::Large, st::radialBg)
, _closeAndContinue(std::move(closeAndContinue)) , _closeAndContinue(std::move(closeAndContinue))
, _destroy(std::move(destroy)) { , _destroy(std::move(destroy)) {
@ -1032,6 +1035,7 @@ void Pip::handleMouseMove(QPoint position) {
}); });
setOverState(computeState(position)); setOverState(computeState(position));
seekUpdate(position); seekUpdate(position);
volumeControllerUpdate(position);
} }
void Pip::setOverState(OverState state) { void Pip::setOverState(OverState state) {
@ -1088,6 +1092,8 @@ void Pip::updateActiveState(OverState was) {
check(_enlarge); check(_enlarge);
check(_play); check(_play);
check(_playback); check(_playback);
check(_volumeToggle);
check(_volumeController);
} }
void Pip::handleMousePress(QPoint position, Qt::MouseButton button) { void Pip::handleMousePress(QPoint position, Qt::MouseButton button) {
@ -1101,10 +1107,11 @@ void Pip::handleMousePress(QPoint position, Qt::MouseButton button) {
return; return;
} }
_pressed = _over; _pressed = _over;
if (_over == OverState::Playback) { if (_over == OverState::Playback || _over == OverState::VolumeController) {
_panel.setDragDisabled(true); _panel.setDragDisabled(true);
} }
seekUpdate(position); seekUpdate(position);
volumeControllerUpdate(position);
} }
void Pip::handleMouseRelease(QPoint position, Qt::MouseButton button) { void Pip::handleMouseRelease(QPoint position, Qt::MouseButton button) {
@ -1118,11 +1125,18 @@ void Pip::handleMouseRelease(QPoint position, Qt::MouseButton button) {
return; return;
} }
seekUpdate(position); seekUpdate(position);
volumeControllerUpdate(position);
const auto pressed = base::take(_pressed); const auto pressed = base::take(_pressed);
if (pressed && *pressed == OverState::Playback) { if (pressed) {
_panel.setDragDisabled(false); if (*pressed == OverState::Playback) {
seekFinish(_playbackProgress->value()); _panel.setDragDisabled(false);
return; seekFinish(_playbackProgress->value());
return;
} else if (*pressed == OverState::VolumeController) {
_panel.setDragDisabled(false);
_panel.update();
return;
}
} else if (_panel.dragging() || !pressed || *pressed != _over) { } else if (_panel.dragging() || !pressed || *pressed != _over) {
_lastHandledPress = std::nullopt; _lastHandledPress = std::nullopt;
return; return;
@ -1132,6 +1146,7 @@ void Pip::handleMouseRelease(QPoint position, Qt::MouseButton button) {
switch (_over) { switch (_over) {
case OverState::Close: _panel.widget()->close(); break; case OverState::Close: _panel.widget()->close(); break;
case OverState::Enlarge: _closeAndContinue(); break; case OverState::Enlarge: _closeAndContinue(); break;
case OverState::VolumeToggle: volumeToggled(); break;
case OverState::Other: playbackPauseResume(); break; case OverState::Other: playbackPauseResume(); break;
} }
} }
@ -1192,10 +1207,37 @@ void Pip::seekFinish(float64 value) {
restartAtSeekPosition(positionMs); restartAtSeekPosition(positionMs);
} }
void Pip::volumeChanged(float64 volume) {
if (volume > 0.) {
_lastPositiveVolume = volume;
}
Player::mixer()->setVideoVolume(volume);
Core::App().settings().setVideoVolume(volume);
Core::App().saveSettingsDelayed();
}
void Pip::volumeToggled() {
const auto volume = Core::App().settings().videoVolume();
volumeChanged(volume ? 0. : _lastPositiveVolume);
_panel.update();
}
void Pip::volumeControllerUpdate(QPoint position) {
if (!_pressed || *_pressed != OverState::VolumeController) {
return;
}
const auto unbound = (position.x() - _volumeController.icon.x())
/ float64(_volumeController.icon.width());
const auto value = std::clamp(unbound, 0., 1.);
volumeChanged(value);
}
void Pip::setupButtons() { void Pip::setupButtons() {
_close.state = OverState::Close; _close.state = OverState::Close;
_enlarge.state = OverState::Enlarge; _enlarge.state = OverState::Enlarge;
_playback.state = OverState::Playback; _playback.state = OverState::Playback;
_volumeToggle.state = OverState::VolumeToggle;
_volumeController.state = OverState::VolumeController;
_play.state = OverState::Other; _play.state = OverState::Other;
_panel.rp()->sizeValue( _panel.rp()->sizeValue(
) | rpl::map([=] { ) | rpl::map([=] {
@ -1212,6 +1254,31 @@ void Pip::setupButtons() {
rect.y(), rect.y(),
st::pipEnlargeIcon.width() + 2 * skip, st::pipEnlargeIcon.width() + 2 * skip,
st::pipEnlargeIcon.height() + 2 * skip); st::pipEnlargeIcon.height() + 2 * skip);
const auto volumeSkip = st::pipPlaybackSkip;
const auto volumeHeight = 2 * volumeSkip + st::pipPlaybackWide;
const auto volumeToggleWidth = st::mediaviewVolumeIcon0.width()
+ 2 * skip;
const auto volumeToggleHeight = st::mediaviewVolumeIcon0.height()
+ 2 * skip;
const auto volumeWidth = (((st::mediaviewVolumeWidth + 2 * skip)
+ _close.area.width()
+ _enlarge.area.width()
+ volumeToggleWidth) < rect.width())
? st::mediaviewVolumeWidth
: 0;
_volumeController.area = QRect(
rect.x() + rect.width() - volumeWidth - 2 * volumeSkip,
rect.y() + (volumeToggleHeight - volumeHeight) / 2,
volumeWidth,
volumeHeight);
_volumeToggle.area = QRect(
_volumeController.area.x()
- st::mediaviewVolumeIcon0.width()
- skip,
rect.y(),
volumeToggleWidth,
volumeToggleHeight);
if (!IsWindowControlsOnLeft()) { if (!IsWindowControlsOnLeft()) {
_close.area.moveLeft(rect.x() _close.area.moveLeft(rect.x()
+ rect.width() + rect.width()
@ -1221,15 +1288,22 @@ void Pip::setupButtons() {
+ rect.width() + rect.width()
- (_enlarge.area.x() - rect.x()) - (_enlarge.area.x() - rect.x())
- _enlarge.area.width()); - _enlarge.area.width());
_volumeToggle.area.moveLeft(rect.x());
_volumeController.area.moveLeft(_volumeToggle.area.x()
+ _volumeToggle.area.width());
} }
_close.icon = _close.area.marginsRemoved({ skip, skip, skip, skip }); _close.icon = _close.area.marginsRemoved({ skip, skip, skip, skip });
_enlarge.icon = _enlarge.area.marginsRemoved( _enlarge.icon = _enlarge.area.marginsRemoved(
{ skip, skip, skip, skip }); { skip, skip, skip, skip });
_volumeToggle.icon = _volumeToggle.area.marginsRemoved(
{ skip, skip, skip, skip });
_play.icon = QRect( _play.icon = QRect(
rect.x() + (rect.width() - st::pipPlayIcon.width()) / 2, rect.x() + (rect.width() - st::pipPlayIcon.width()) / 2,
rect.y() + (rect.height() - st::pipPlayIcon.height()) / 2, rect.y() + (rect.height() - st::pipPlayIcon.height()) / 2,
st::pipPlayIcon.width(), st::pipPlayIcon.width(),
st::pipPlayIcon.height()); st::pipPlayIcon.height());
_volumeController.icon = _volumeController.area.marginsRemoved(
{ volumeSkip, volumeSkip, volumeSkip, volumeSkip });
const auto playbackSkip = st::pipPlaybackSkip; const auto playbackSkip = st::pipPlaybackSkip;
const auto playbackHeight = 2 * playbackSkip + st::pipPlaybackWide; const auto playbackHeight = 2 * playbackSkip + st::pipPlaybackWide;
_playback.area = QRect( _playback.area = QRect(
@ -1312,6 +1386,7 @@ void Pip::paintControls(QPainter &p) const {
paintButtons(p); paintButtons(p);
paintPlayback(p); paintPlayback(p);
paintPlaybackTexts(p); paintPlaybackTexts(p);
paintVolumeController(p);
} }
void Pip::paintFade(QPainter &p) const { void Pip::paintFade(QPainter &p) const {
@ -1355,42 +1430,73 @@ void Pip::paintButtons(QPainter &p) const {
_showPause ? st::pipPauseIconOver : st::pipPlayIconOver); _showPause ? st::pipPauseIconOver : st::pipPlayIconOver);
drawOne(_close, st::pipCloseIcon, st::pipCloseIconOver); drawOne(_close, st::pipCloseIcon, st::pipCloseIconOver);
drawOne(_enlarge, st::pipEnlargeIcon, st::pipEnlargeIconOver); drawOne(_enlarge, st::pipEnlargeIcon, st::pipEnlargeIconOver);
const auto volume = Core::App().settings().videoVolume();
if (volume <= 0.) {
drawOne(
_volumeToggle,
st::mediaviewVolumeIcon0,
st::mediaviewVolumeIcon0Over);
} else if (volume < 1 / 2.) {
drawOne(
_volumeToggle,
st::mediaviewVolumeIcon1,
st::mediaviewVolumeIcon1Over);
} else {
drawOne(
_volumeToggle,
st::mediaviewVolumeIcon2,
st::mediaviewVolumeIcon2Over);
}
} }
void Pip::paintPlayback(QPainter &p) const { void Pip::paintPlayback(QPainter &p) const {
const auto radius = _playback.icon.height() / 2; const auto radius = _playback.icon.height() / 2;
const auto shown = activeValue(_playback);
const auto progress = _playbackProgress->value(); const auto progress = _playbackProgress->value();
const auto width = _playback.icon.width();
const auto height = anim::interpolate( const auto height = anim::interpolate(
st::pipPlaybackWidth, st::pipPlaybackWidth,
_playback.icon.height(), _playback.icon.height(),
activeValue(_playback)); activeValue(_playback));
const auto left = _playback.icon.x(); const auto rect = QRect(
const auto top = _playback.icon.y() + _playback.icon.height() - height; _playback.icon.x(),
const auto done = int(std::round(width * progress)); _playback.icon.y() + _playback.icon.height() - height,
_playback.icon.width(),
height);
paintProgressBar(p, rect, progress, radius);
}
void Pip::paintProgressBar(
QPainter &p,
const QRect &rect,
float64 progress,
int radius) const {
const auto done = int(std::round(rect.width() * progress));
PainterHighQualityEnabler hq(p); PainterHighQualityEnabler hq(p);
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
if (done > 0) { if (done > 0) {
p.setBrush(st::mediaviewPipPlaybackActive); p.setBrush(st::mediaviewPipPlaybackActive);
p.setClipRect(left, top, done, height); p.setClipRect(rect.x(), rect.y(), done, rect.height());
p.drawRoundedRect( p.drawRoundedRect(
left, rect.x(),
top, rect.y(),
std::min(done + radius, width), std::min(done + radius, rect.width()),
height, rect.height(),
radius, radius,
radius); radius);
} }
if (done < width) { if (done < rect.width()) {
const auto from = std::max(left + done - radius, left); const auto from = std::max(rect.x() + done - radius, rect.x());
p.setBrush(st::mediaviewPipPlaybackInactive); p.setBrush(st::mediaviewPipPlaybackInactive);
p.setClipRect(left + done, top, width - done, height); p.setClipRect(
rect.x() + done,
rect.y(),
rect.width() - done,
rect.height());
p.drawRoundedRect( p.drawRoundedRect(
from, from,
top, rect.y(),
left + width - from, rect.x() + rect.width() - from,
height, rect.height(),
radius, radius,
radius); radius);
} }
@ -1412,6 +1518,25 @@ void Pip::paintPlaybackTexts(QPainter &p) const {
p.drawText(right - _timeLeftWidth, top, _timeLeft); p.drawText(right - _timeLeftWidth, top, _timeLeft);
} }
void Pip::paintVolumeController(QPainter &p) const {
if (!_volumeController.icon.width()) {
return;
}
const auto radius = _volumeController.icon.height() / 2;
const auto volume = Core::App().settings().videoVolume();
const auto height = anim::interpolate(
st::pipPlaybackWidth,
_volumeController.icon.height(),
activeValue(_volumeController));
const auto rect = QRect(
_volumeController.icon.x(),
_volumeController.icon.y() + radius - height / 2,
_volumeController.icon.width(),
height);
paintProgressBar(p, rect, volume, radius);
}
void Pip::handleStreamingUpdate(Streaming::Update &&update) { void Pip::handleStreamingUpdate(Streaming::Update &&update) {
using namespace Streaming; using namespace Streaming;
@ -1703,6 +1828,10 @@ Pip::OverState Pip::computeState(QPoint position) const {
return OverState::Enlarge; return OverState::Enlarge;
} else if (_playback.area.contains(position)) { } else if (_playback.area.contains(position)) {
return OverState::Playback; return OverState::Playback;
} else if (_volumeToggle.area.contains(position)) {
return OverState::VolumeToggle;
} else if (_volumeController.area.contains(position)) {
return OverState::VolumeController;
} else { } else {
return OverState::Other; return OverState::Other;
} }

View file

@ -144,6 +144,8 @@ private:
Close, Close,
Enlarge, Enlarge,
Playback, Playback,
VolumeToggle,
VolumeController,
Other, Other,
}; };
enum class ThumbState { enum class ThumbState {
@ -166,6 +168,9 @@ private:
void setupStreaming(); void setupStreaming();
void paint(QPainter &p, FrameRequest request, bool opengl); void paint(QPainter &p, FrameRequest request, bool opengl);
void playbackPauseResume(); void playbackPauseResume();
void volumeChanged(float64 volume);
void volumeToggled();
void volumeControllerUpdate(QPoint position);
void waitingAnimationCallback(); void waitingAnimationCallback();
void handleStreamingUpdate(Streaming::Update &&update); void handleStreamingUpdate(Streaming::Update &&update);
void handleStreamingError(Streaming::Error &&error); void handleStreamingError(Streaming::Error &&error);
@ -198,7 +203,13 @@ private:
void paintFade(QPainter &p) const; void paintFade(QPainter &p) const;
void paintButtons(QPainter &p) const; void paintButtons(QPainter &p) const;
void paintPlayback(QPainter &p) const; void paintPlayback(QPainter &p) const;
void paintProgressBar(
QPainter &p,
const QRect &rect,
float64 progress,
int radius) const;
void paintPlaybackTexts(QPainter &p) const; void paintPlaybackTexts(QPainter &p) const;
void paintVolumeController(QPainter &p) const;
void paintRadialLoading(QPainter &p) const; void paintRadialLoading(QPainter &p) const;
void paintRadialLoadingContent(QPainter &p, const QRect &inner) const; void paintRadialLoadingContent(QPainter &p, const QRect &inner) const;
[[nodiscard]] QRect countRadialRect() const; [[nodiscard]] QRect countRadialRect() const;
@ -222,6 +233,7 @@ private:
QString _timeAlready, _timeLeft; QString _timeAlready, _timeLeft;
int _timeLeftWidth = 0; int _timeLeftWidth = 0;
int _rotation = 0; int _rotation = 0;
float64 _lastPositiveVolume = 1.;
crl::time _seekPositionMs = -1; crl::time _seekPositionMs = -1;
crl::time _lastDurationMs = 0; crl::time _lastDurationMs = 0;
OverState _over = OverState::None; OverState _over = OverState::None;
@ -231,6 +243,8 @@ private:
Button _enlarge; Button _enlarge;
Button _playback; Button _playback;
Button _play; Button _play;
Button _volumeToggle;
Button _volumeController;
Ui::Animations::Simple _controlsShown; Ui::Animations::Simple _controlsShown;
Ui::RoundRect _roundRect; Ui::RoundRect _roundRect;