From ce1973fd3069801b54b938647016b3c0c67b0e0b Mon Sep 17 00:00:00 2001 From: John Preston Date: Sat, 17 Sep 2016 22:28:33 +0300 Subject: [PATCH] New media player layout started. --- Telegram/SourceFiles/mainwidget.cpp | 11 ++ Telegram/SourceFiles/mainwidget.h | 7 + .../media/player/media_player.style | 60 ++++++ .../media/player/media_player_cover.cpp | 36 ++++ .../media/player/media_player_cover.h | 31 +++ .../media/player/media_player_list.h | 5 + .../media/player/media_player_playback.cpp | 11 ++ .../media/player/media_player_playback.h | 11 ++ .../player/media_player_volume_controller.cpp | 24 +++ .../player/media_player_volume_controller.h | 14 ++ .../media/player/media_player_widget.cpp | 177 ++++++++++++++++++ .../media/player/media_player_widget.h | 57 ++++++ Telegram/SourceFiles/title.h | 4 + 13 files changed, 448 insertions(+) diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index dfcfe94ab..ff5765320 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -50,6 +50,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "localstorage.h" #include "shortcuts.h" #include "media/media_audio.h" +#include "media/player/media_player_button.h" +#include "media/player/media_player_widget.h" #include "core/qthelp_regex.h" #include "core/qthelp_url.h" #include "window/chat_background.h" @@ -75,6 +77,11 @@ MainWidget::MainWidget(MainWindow *window) : TWidget(window) , _api(new ApiWrap(this)) { setGeometry(QRect(0, st::titleHeight, App::wnd()->width(), App::wnd()->height() - st::titleHeight)); + if (!_mediaPlayer) { + _mediaPlayer = new Media::Player::Widget(this); + App::wnd()->getTitle()->playerButton()->installEventFilter(_mediaPlayer); + } + MTP::setGlobalDoneHandler(rpcDone(&MainWidget::updateReceived)); _ptsWaiter.setRequesting(true); updateScrollColors(); @@ -2405,6 +2412,7 @@ void MainWidget::orderWidgets() { _dialogs->raise(); _mediaType->raise(); _sideShadow.raise(); + if (_mediaPlayer) _mediaPlayer->raise(); if (_hider) _hider->raise(); } @@ -2664,6 +2672,9 @@ inline int chatsListWidth(int windowWidth) { void MainWidget::resizeEvent(QResizeEvent *e) { int32 tbh = _topBar->isHidden() ? 0 : st::topBarHeight; + if (_mediaPlayer) { + _mediaPlayer->moveToRight(0, 0); + } if (Adaptive::OneColumn()) { _dialogsWidth = width(); _player->setGeometry(0, 0, _dialogsWidth, _player->height()); diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 939494967..657f944a4 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -27,6 +27,12 @@ namespace Dialogs { class Row; } // namespace Dialogs +namespace Media { +namespace Player { +class Widget; +} // namespace Player +} // namespace Media + namespace Ui { class PeerAvatarButton; } // namespace Ui @@ -580,6 +586,7 @@ private: ChildWidget _overview = { nullptr }; ChildWidget _player; ChildWidget _topBar; + ChildWidget _mediaPlayer = { nullptr }; ConfirmBox *_forwardConfirm = nullptr; // for single column layout ChildWidget _hider = { nullptr }; std_::vector_of_moveable> _stack; diff --git a/Telegram/SourceFiles/media/player/media_player.style b/Telegram/SourceFiles/media/player/media_player.style index 1113a7fd9..a71a64813 100644 --- a/Telegram/SourceFiles/media/player/media_player.style +++ b/Telegram/SourceFiles/media/player/media_player.style @@ -31,3 +31,63 @@ mediaPlayerTitleButtonPauseTop: 8px; mediaPlayerTitleButtonPauseStroke: 3px; mediaPlayerTitleButtonPlayLeft: 10px; mediaPlayerTitleButtonPlayTop: 7px; + +mediaPlayerMarginLeft: 10px; +mediaPlayerMarginBottom: 10px; +mediaPlayerWidth: 344px; +mediaPlayerCoverHeight: 102px; + +mediaPlayerPlayButton: IconButton { + width: 32px; + height: 32px; + + opacity: 1.; + overOpacity: 1.; + + icon: icon { + { "player_play", #54b5ed, point(6px, 7px) }, + }; + iconPosition: point(0px, 0px); + downIconPosition: point(0px, 0px); + + duration: 0; +} +mediaPlayerPauseIcon: icon { + { "player_pause", #54b5ed, point(9px, 8px) } +}; + +mediaPlayerRepeatButton: IconButton(mediaPlayerPlayButton) { + icon: icon { + { "player_repeat", #54b5ed, point(9px, 9px)} + }; +} + +mediaPlayerPadding: 18px; +mediaPlayerNameTop: 24px; +mediaPlayerPlayLeft: 9px; +mediaPlayerPlayTop: 58px; +mediaPlayerNameFont: normalFont; +mediaPlayerNameFg: windowTextFg; +mediaPlayerTimeFont: normalFont; +mediaPlayerTimeFg: windowSubTextFg; +mediaPlayerPlaybackTop: 32px; +mediaPlayerPlaybackPadding: 8px; +mediaPlayerPlaybackBg: #54b5ed; +mediaPlayerPlaybackLine: 3px; + +mediaPlayerVolumeRight: 50px; +mediaPlayerVolumeWidth: 86px; +mediaPlayerVolumeLength: 64px; + +mediaPlayerVolumeIcon0: icon { + { "player_volume0", #54b5ed }, +}; +mediaPlayerVolumeIcon1: icon { + { "player_volume1", #54b5ed }, +}; +mediaPlayerVolumeIcon2: icon { + { "player_volume2", #54b5ed }, +}; +mediaPlayerVolumeIcon3: icon { + { "player_volume3", #54b5ed }, +}; diff --git a/Telegram/SourceFiles/media/player/media_player_cover.cpp b/Telegram/SourceFiles/media/player/media_player_cover.cpp index aa7c0de49..c1c4165fb 100644 --- a/Telegram/SourceFiles/media/player/media_player_cover.cpp +++ b/Telegram/SourceFiles/media/player/media_player_cover.cpp @@ -21,8 +21,44 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "stdafx.h" #include "media/player/media_player_cover.h" +#include "ui/flatlabel.h" +#include "ui/widgets/label_simple.h" +#include "ui/buttons/icon_button.h" +#include "media/player/media_player_playback.h" +#include "media/player/media_player_volume_controller.h" +#include "styles/style_media_player.h" + namespace Media { namespace Player { +CoverWidget::CoverWidget(QWidget *parent) : TWidget(parent) +, _nameLabel(this) +, _timeLabel(this) +, _playback(this) +, _playPause(this, st::mediaPlayerPlayButton) +, _volumeController(this) +, _repeatTrack(this, st::mediaPlayerRepeatButton) { + setAttribute(Qt::WA_OpaquePaintEvent); + _playPause->setIcon(&st::mediaPlayerPauseIcon); +} + +void CoverWidget::resizeEvent(QResizeEvent *e) { + _nameLabel->moveToLeft(st::mediaPlayerPadding, st::mediaPlayerNameTop - st::mediaPlayerNameFont->ascent); + _timeLabel->moveToRight(st::mediaPlayerPadding, st::mediaPlayerNameTop - st::mediaPlayerTimeFont->ascent); + _playback->setGeometry(st::mediaPlayerPadding, st::mediaPlayerPlaybackTop, width() - 2 * st::mediaPlayerPadding, 2 * st::mediaPlayerPlaybackPadding + st::mediaPlayerPlaybackLine); + _repeatTrack->moveToRight(st::mediaPlayerPlayLeft, st::mediaPlayerPlayTop); + _volumeController->moveToRight(st::mediaPlayerVolumeRight, st::mediaPlayerPlayTop + (_playPause->height() - _volumeController->height()) / 2); + updatePlayPrevNextPositions(); +} + +void CoverWidget::paintEvent(QPaintEvent *e) { + Painter p(this); + p.fillRect(e->rect(), st::windowBg); +} + +void CoverWidget::updatePlayPrevNextPositions() { + _playPause->moveToLeft(st::mediaPlayerPlayLeft, st::mediaPlayerPlayTop); +} + } // namespace Player } // namespace Media diff --git a/Telegram/SourceFiles/media/player/media_player_cover.h b/Telegram/SourceFiles/media/player/media_player_cover.h index 948c76012..f5ed19de3 100644 --- a/Telegram/SourceFiles/media/player/media_player_cover.h +++ b/Telegram/SourceFiles/media/player/media_player_cover.h @@ -20,8 +20,39 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once +class FlatLabel; +namespace Ui { +class LabelSimple; +class IconButton; +} // namespace Ui + namespace Media { namespace Player { +class PlaybackWidget; +class VolumeController; + +class CoverWidget : public TWidget { +public: + CoverWidget(QWidget *parent); + +protected: + void resizeEvent(QResizeEvent *e) override; + void paintEvent(QPaintEvent *e) override; + +private: + void updatePlayPrevNextPositions(); + + ChildWidget _nameLabel; + ChildWidget _timeLabel; + ChildWidget _playback; + ChildWidget _previousTrack = { nullptr }; + ChildWidget _playPause; + ChildWidget _nextTrack = { nullptr }; + ChildWidget _volumeController; + ChildWidget _repeatTrack; + +}; + } // namespace Clip } // namespace Media diff --git a/Telegram/SourceFiles/media/player/media_player_list.h b/Telegram/SourceFiles/media/player/media_player_list.h index 948c76012..53410092b 100644 --- a/Telegram/SourceFiles/media/player/media_player_list.h +++ b/Telegram/SourceFiles/media/player/media_player_list.h @@ -23,5 +23,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org namespace Media { namespace Player { +class ListWidget : public ScrolledWidget { +public: + +}; + } // namespace Clip } // namespace Media diff --git a/Telegram/SourceFiles/media/player/media_player_playback.cpp b/Telegram/SourceFiles/media/player/media_player_playback.cpp index 43665cec4..21839405f 100644 --- a/Telegram/SourceFiles/media/player/media_player_playback.cpp +++ b/Telegram/SourceFiles/media/player/media_player_playback.cpp @@ -21,8 +21,19 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "stdafx.h" #include "media/player/media_player_playback.h" +#include "styles/style_media_player.h" + namespace Media { namespace Player { +PlaybackWidget::PlaybackWidget(QWidget *parent) : TWidget(parent) { +} + +void PlaybackWidget::paintEvent(QPaintEvent *e) { + Painter p(this); + + p.fillRect(0, st::mediaPlayerPlaybackPadding, width(), st::mediaPlayerPlaybackLine, st::mediaPlayerPlaybackBg); +} + } // namespace Player } // namespace Media diff --git a/Telegram/SourceFiles/media/player/media_player_playback.h b/Telegram/SourceFiles/media/player/media_player_playback.h index 948c76012..83596c663 100644 --- a/Telegram/SourceFiles/media/player/media_player_playback.h +++ b/Telegram/SourceFiles/media/player/media_player_playback.h @@ -23,5 +23,16 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org namespace Media { namespace Player { +class PlaybackWidget : public TWidget { +public: + PlaybackWidget(QWidget *parent); + +protected: + void paintEvent(QPaintEvent *e) override; + +private: + +}; + } // namespace Clip } // namespace Media diff --git a/Telegram/SourceFiles/media/player/media_player_volume_controller.cpp b/Telegram/SourceFiles/media/player/media_player_volume_controller.cpp index d9ac5dda0..41b8087a0 100644 --- a/Telegram/SourceFiles/media/player/media_player_volume_controller.cpp +++ b/Telegram/SourceFiles/media/player/media_player_volume_controller.cpp @@ -21,8 +21,32 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "stdafx.h" #include "media/player/media_player_volume_controller.h" +#include "styles/style_media_player.h" + namespace Media { namespace Player { +VolumeController::VolumeController(QWidget *parent) : TWidget(parent) { + resize(st::mediaPlayerVolumeWidth, 2 * st::mediaPlayerPlaybackPadding + st::mediaPlayerPlaybackLine); +} + +void VolumeController::paintEvent(QPaintEvent *e) { + Painter p(this); + + st::mediaPlayerVolumeIcon0.paint(p, QPoint(0, (height() - st::mediaPlayerVolumeIcon0.height()) / 2), width()); + + auto left = rtl() ? 0 : width() - st::mediaPlayerVolumeLength; + p.fillRect(left, st::mediaPlayerPlaybackPadding, st::mediaPlayerVolumeLength, st::mediaPlayerPlaybackLine, st::mediaPlayerPlaybackBg); +} + +void VolumeController::mousePressEvent(QMouseEvent *e) { +} + +void VolumeController::mouseMoveEvent(QMouseEvent *e) { +} + +void VolumeController::mouseReleaseEvent(QMouseEvent *e) { +} + } // namespace Player } // namespace Media diff --git a/Telegram/SourceFiles/media/player/media_player_volume_controller.h b/Telegram/SourceFiles/media/player/media_player_volume_controller.h index 948c76012..8c4c90412 100644 --- a/Telegram/SourceFiles/media/player/media_player_volume_controller.h +++ b/Telegram/SourceFiles/media/player/media_player_volume_controller.h @@ -23,5 +23,19 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org namespace Media { namespace Player { +class VolumeController : public TWidget { +public: + VolumeController(QWidget *parent); + +protected: + void paintEvent(QPaintEvent *e) override; + void mousePressEvent(QMouseEvent *e) override; + void mouseMoveEvent(QMouseEvent *e) override; + void mouseReleaseEvent(QMouseEvent *e) override; + +private: + +}; + } // namespace Clip } // namespace Media diff --git a/Telegram/SourceFiles/media/player/media_player_widget.cpp b/Telegram/SourceFiles/media/player/media_player_widget.cpp index db1a34e90..7e58821f1 100644 --- a/Telegram/SourceFiles/media/player/media_player_widget.cpp +++ b/Telegram/SourceFiles/media/player/media_player_widget.cpp @@ -21,8 +21,185 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "stdafx.h" #include "media/player/media_player_widget.h" +#include "media/player/media_player_cover.h" +#include "media/player/media_player_list.h" +#include "styles/style_media_player.h" +#include "mainwindow.h" + namespace Media { namespace Player { +Widget::Widget(QWidget *parent) : TWidget(parent) +, _shadow(st::defaultInnerDropdown.shadow) +, _cover(this) { + _hideTimer.setSingleShot(true); + connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(onHideStart())); + + _showTimer.setSingleShot(true); + connect(&_showTimer, SIGNAL(timeout()), this, SLOT(onShowStart())); + + connect(_scroll, SIGNAL(scrolled()), this, SLOT(onScroll())); + + if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) { + connect(App::wnd()->windowHandle(), SIGNAL(activeChanged()), this, SLOT(onWindowActiveChanged())); + } + + hide(); + resize(contentLeft() + st::mediaPlayerWidth, st::mediaPlayerCoverHeight + st::mediaPlayerMarginBottom); +} + +bool Widget::overlaps(const QRect &globalRect) { + if (isHidden() || !_a_appearance.isNull()) return false; + + auto marginLeft = rtl() ? 0 : contentLeft(); + auto marginRight = rtl() ? contentLeft() : 0; + return rect().marginsRemoved(QMargins(marginLeft, 0, marginRight, st::mediaPlayerMarginBottom)).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size())); +} + +void Widget::onWindowActiveChanged() { + if (!App::wnd()->windowHandle()->isActive() && !isHidden()) { + leaveEvent(nullptr); + } +} + +void Widget::resizeEvent(QResizeEvent *e) { + _cover->resize(width() - contentLeft(), st::mediaPlayerCoverHeight); + _cover->moveToRight(0, 0); + if (_scroll) { + _scroll->resize(width(), height() - _cover->height()); + _scroll->moveToRight(0, _cover->height()); + _list->resizeToWidth(width()); + } + //_scroll->setGeometry(rect().marginsRemoved(_st.padding).marginsRemoved(_st.scrollMargin)); + //if (auto widget = static_cast(_scroll->widget())) { + // widget->resizeToWidth(_scroll->width()); + // onScroll(); + //} +} + +void Widget::onScroll() { + //if (auto widget = static_cast(_scroll->widget())) { + // int visibleTop = _scroll->scrollTop(); + // int visibleBottom = visibleTop + _scroll->height(); + // widget->setVisibleTopBottom(visibleTop, visibleBottom); + //} +} + +void Widget::paintEvent(QPaintEvent *e) { + Painter p(this); + + if (!_cache.isNull()) { + bool animating = _a_appearance.animating(getms()); + if (animating) { + p.setOpacity(_a_appearance.current(_hiding)); + } else if (_hiding) { + hidingFinished(); + return; + } + p.drawPixmap(0, 0, _cache); + if (!animating) { + showChildren(); + _cache = QPixmap(); + } + return; + } + + // draw shadow + auto shadowedRect = myrtlrect(contentLeft(), 0, contentWidth(), height() - st::mediaPlayerMarginBottom); + auto shadowedSides = (rtl() ? Ui::RectShadow::Side::Right : Ui::RectShadow::Side::Left) | Ui::RectShadow::Side::Bottom; + _shadow.paint(p, shadowedRect, st::defaultInnerDropdown.shadowShift, shadowedSides); + p.fillRect(shadowedRect, st::windowBg); +} + +void Widget::enterEvent(QEvent *e) { + _hideTimer.stop(); + if (_a_appearance.animating(getms())) { + onShowStart(); + } else { + _showTimer.start(0); + } + return TWidget::enterEvent(e); +} + +void Widget::leaveEvent(QEvent *e) { + _showTimer.stop(); + if (_a_appearance.animating(getms())) { + onHideStart(); + } else { + _hideTimer.start(300); + } + return TWidget::leaveEvent(e); +} + +void Widget::otherEnter() { + _hideTimer.stop(); + if (_a_appearance.animating(getms())) { + onShowStart(); + } else { + _showTimer.start(300); + } +} + +void Widget::otherLeave() { + _showTimer.stop(); + if (_a_appearance.animating(getms())) { + onHideStart(); + } else { + _hideTimer.start(0); + } +} + +void Widget::onShowStart() { + if (isHidden()) { + show(); + } else if (!_hiding) { + return; + } + _hiding = false; + startAnimation(); +} + +void Widget::onHideStart() { + if (_hiding) return; + + _hiding = true; + startAnimation(); +} + +void Widget::startAnimation() { + auto from = _hiding ? 1. : 0.; + auto to = _hiding ? 0. : 1.; + if (_a_appearance.isNull()) { + showChildren(); + _cache = myGrab(this); + } + hideChildren(); + START_ANIMATION(_a_appearance, func([this]() { + update(); + if (!_a_appearance.animating(getms()) && _hiding) { + _hiding = false; + hidingFinished(); + } + }), from, to, st::defaultInnerDropdown.duration, anim::linear); +} + +void Widget::hidingFinished() { + hide(); + showChildren(); +} + +int Widget::contentLeft() const { + return st::mediaPlayerMarginLeft; +} + +bool Widget::eventFilter(QObject *obj, QEvent *e) { + if (e->type() == QEvent::Enter) { + otherEnter(); + } else if (e->type() == QEvent::Leave) { + otherLeave(); + } + return false; +} + } // namespace Player } // namespace Media diff --git a/Telegram/SourceFiles/media/player/media_player_widget.h b/Telegram/SourceFiles/media/player/media_player_widget.h index 948c76012..44c01ca91 100644 --- a/Telegram/SourceFiles/media/player/media_player_widget.h +++ b/Telegram/SourceFiles/media/player/media_player_widget.h @@ -20,8 +20,65 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once +#include "ui/boxshadow.h" + +class ScrollArea; + namespace Media { namespace Player { +class CoverWidget; +class ListWidget; + +class Widget : public TWidget { + Q_OBJECT + +public: + Widget(QWidget *parent); + + bool overlaps(const QRect &globalRect); + + void otherEnter(); + void otherLeave(); + +protected: + void resizeEvent(QResizeEvent *e) override; + void paintEvent(QPaintEvent *e) override; + void enterEvent(QEvent *e) override; + void leaveEvent(QEvent *e) override; + + bool eventFilter(QObject *obj, QEvent *e) override; + +private slots: + void onShowStart(); + void onHideStart(); + void onScroll(); + + void onWindowActiveChanged(); + +private: + void hidingFinished(); + int contentLeft() const; + int contentWidth() const { + return width() - contentLeft(); + } + + void startAnimation(); + + bool _hiding = false; + + QPixmap _cache; + FloatAnimation _a_appearance; + + QTimer _hideTimer, _showTimer; + + Ui::RectShadow _shadow; + ChildWidget _cover; + ChildWidget _list = { nullptr }; + ChildWidget _scroll = { nullptr }; + + +}; + } // namespace Clip } // namespace Media diff --git a/Telegram/SourceFiles/title.h b/Telegram/SourceFiles/title.h index 72ffb0220..cb98ca335 100644 --- a/Telegram/SourceFiles/title.h +++ b/Telegram/SourceFiles/title.h @@ -61,6 +61,10 @@ public: void maximizedChanged(bool maximized, bool force = false); + Media::Player::TitleButton *playerButton() { + return _player; + } + HitTestType hitTest(const QPoint &p); void setHideLevel(float64 level);