Media::Player::Widget added instead of PlayerWidget.
New media player bar widget added. Switching between floating media player panel and media player widget. New volume controller.
|
@ -2035,33 +2035,6 @@ botDescSkip: 8px;
|
||||||
suppressAll: 0.2;
|
suppressAll: 0.2;
|
||||||
suppressSong: 0.05;
|
suppressSong: 0.05;
|
||||||
|
|
||||||
playerHeight: 44px;
|
|
||||||
playerBg: #e4e9ef;
|
|
||||||
playerFg: #54748f;
|
|
||||||
playerTimeFg: #a4afba;
|
|
||||||
playerLineHeight: 3px;
|
|
||||||
playerMoverSize: size(2px, 7px);
|
|
||||||
playerLineActive: #6389a8;
|
|
||||||
playerLineInactive: #bac7d4;
|
|
||||||
playerSkip: 8px;
|
|
||||||
playerNameStyle: textStyle(defaultTextStyle) {
|
|
||||||
linkFg: #6389a8;
|
|
||||||
linkFgDown: #6389a8;
|
|
||||||
linkFlags: semiboldFont;
|
|
||||||
linkFlagsOver: semiboldFont;
|
|
||||||
}
|
|
||||||
playerPlay: sprite(377px, 109px, 19px, 22px);
|
|
||||||
playerPause: sprite(379px, 131px, 17px, 20px);
|
|
||||||
playerNext: sprite(374px, 151px, 22px, 14px);
|
|
||||||
playerPrev: sprite(374px, 165px, 22px, 14px);
|
|
||||||
playerClose: sprite(361px, 97px, 12px, 12px);
|
|
||||||
playerFull: sprite(365px, 109px, 12px, 12px);
|
|
||||||
playerRepeat: sprite(365px, 121px, 12px, 14px);
|
|
||||||
playerVolume: sprite(352px, 179px, 44px, 12px);
|
|
||||||
playerInactiveOpacity: 0.8;
|
|
||||||
playerUnavailableOpacity: 0.3;
|
|
||||||
playerDuration: 200;
|
|
||||||
|
|
||||||
inlineResultsLeft: 11px;
|
inlineResultsLeft: 11px;
|
||||||
inlineResultsSkip: 3px;
|
inlineResultsSkip: 3px;
|
||||||
inlineMediaHeight: 96px;
|
inlineMediaHeight: 96px;
|
||||||
|
|
After Width: | Height: | Size: 133 B |
After Width: | Height: | Size: 197 B |
Before Width: | Height: | Size: 188 B After Width: | Height: | Size: 219 B |
Before Width: | Height: | Size: 297 B After Width: | Height: | Size: 319 B |
After Width: | Height: | Size: 188 B |
After Width: | Height: | Size: 297 B |
After Width: | Height: | Size: 349 B |
After Width: | Height: | Size: 547 B |
After Width: | Height: | Size: 182 B |
After Width: | Height: | Size: 292 B |
Before Width: | Height: | Size: 182 B After Width: | Height: | Size: 201 B |
Before Width: | Height: | Size: 292 B After Width: | Height: | Size: 325 B |
Before Width: | Height: | Size: 299 B After Width: | Height: | Size: 264 B |
|
@ -400,9 +400,9 @@ namespace {
|
||||||
|
|
||||||
switch (user.type()) {
|
switch (user.type()) {
|
||||||
case mtpc_userEmpty: {
|
case mtpc_userEmpty: {
|
||||||
auto &d(user.c_userEmpty());
|
auto &d = user.c_userEmpty();
|
||||||
|
|
||||||
PeerId peer(peerFromUser(d.vid.v));
|
auto peer = peerFromUser(d.vid.v);
|
||||||
data = App::user(peer);
|
data = App::user(peer);
|
||||||
auto canShareThisContact = data->canShareThisContactFast();
|
auto canShareThisContact = data->canShareThisContactFast();
|
||||||
wasContact = data->isContact();
|
wasContact = data->isContact();
|
||||||
|
@ -421,10 +421,10 @@ namespace {
|
||||||
if (wasContact != data->isContact()) update.flags |= UpdateFlag::UserIsContact;
|
if (wasContact != data->isContact()) update.flags |= UpdateFlag::UserIsContact;
|
||||||
} break;
|
} break;
|
||||||
case mtpc_user: {
|
case mtpc_user: {
|
||||||
auto &d(user.c_user());
|
auto &d = user.c_user();
|
||||||
minimal = d.is_min();
|
minimal = d.is_min();
|
||||||
|
|
||||||
PeerId peer(peerFromUser(d.vid.v));
|
auto peer = peerFromUser(d.vid.v);
|
||||||
data = App::user(peer);
|
data = App::user(peer);
|
||||||
auto canShareThisContact = data->canShareThisContactFast();
|
auto canShareThisContact = data->canShareThisContactFast();
|
||||||
wasContact = data->isContact();
|
wasContact = data->isContact();
|
||||||
|
@ -1095,11 +1095,11 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkEntitiesAndViewsUpdate(const MTPDmessage &m) {
|
bool checkEntitiesAndViewsUpdate(const MTPDmessage &m) {
|
||||||
PeerId peerId = peerFromMTP(m.vto_id);
|
auto peerId = peerFromMTP(m.vto_id);
|
||||||
if (m.has_from_id() && peerToUser(peerId) == MTP::authedId()) {
|
if (m.has_from_id() && peerToUser(peerId) == MTP::authedId()) {
|
||||||
peerId = peerFromUser(m.vfrom_id);
|
peerId = peerFromUser(m.vfrom_id);
|
||||||
}
|
}
|
||||||
if (HistoryItem *existing = App::histItemById(peerToChannel(peerId), m.vid.v)) {
|
if (auto existing = App::histItemById(peerToChannel(peerId), m.vid.v)) {
|
||||||
auto text = qs(m.vmessage);
|
auto text = qs(m.vmessage);
|
||||||
auto entities = m.has_entities() ? entitiesFromMTP(m.ventities.c_vector().v) : EntitiesInText();
|
auto entities = m.has_entities() ? entitiesFromMTP(m.ventities.c_vector().v) : EntitiesInText();
|
||||||
existing->setText({ text, entities });
|
existing->setText({ text, entities });
|
||||||
|
@ -1951,7 +1951,7 @@ namespace {
|
||||||
HistoryItem *histItemById(ChannelId channelId, MsgId itemId) {
|
HistoryItem *histItemById(ChannelId channelId, MsgId itemId) {
|
||||||
if (!itemId) return nullptr;
|
if (!itemId) return nullptr;
|
||||||
|
|
||||||
MsgsData *data = fetchMsgsData(channelId, false);
|
auto data = fetchMsgsData(channelId, false);
|
||||||
if (!data) return nullptr;
|
if (!data) return nullptr;
|
||||||
|
|
||||||
auto i = data->constFind(itemId);
|
auto i = data->constFind(itemId);
|
||||||
|
|
|
@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "layerwidget.h"
|
#include "layerwidget.h"
|
||||||
|
#include "ui/widgets/shadow.h"
|
||||||
|
|
||||||
class BlueTitleShadow : public TWidget {
|
class BlueTitleShadow : public TWidget {
|
||||||
public:
|
public:
|
||||||
|
@ -93,9 +94,9 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ScrollableBoxShadow : public PlainShadow {
|
class ScrollableBoxShadow : public Ui::PlainShadow {
|
||||||
public:
|
public:
|
||||||
ScrollableBoxShadow(QWidget *parent) : PlainShadow(parent, st::boxScrollShadowBg) {
|
ScrollableBoxShadow(QWidget *parent) : Ui::PlainShadow(parent, st::boxScrollShadowBg) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1359,25 +1359,25 @@ void StickersBox::setup() {
|
||||||
int bottomSkip = st::boxPadding.bottom();
|
int bottomSkip = st::boxPadding.bottom();
|
||||||
if (_section == Section::Installed) {
|
if (_section == Section::Installed) {
|
||||||
_aboutHeight = st::stickersReorderPadding.top() + _about.countHeight(_aboutWidth) + st::stickersReorderPadding.bottom();
|
_aboutHeight = st::stickersReorderPadding.top() + _about.countHeight(_aboutWidth) + st::stickersReorderPadding.bottom();
|
||||||
_topShadow = new PlainShadow(this, st::contactsAboutShadow);
|
_topShadow.create(this, st::contactsAboutShadow);
|
||||||
|
|
||||||
_save = new BoxButton(this, lang(lng_settings_save), st::defaultBoxButton);
|
_save.create(this, lang(lng_settings_save), st::defaultBoxButton);
|
||||||
connect(_save, SIGNAL(clicked()), this, SLOT(onSave()));
|
connect(_save, SIGNAL(clicked()), this, SLOT(onSave()));
|
||||||
|
|
||||||
_cancel = new BoxButton(this, lang(lng_cancel), st::cancelBoxButton);
|
_cancel.create(this, lang(lng_cancel), st::cancelBoxButton);
|
||||||
connect(_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
|
connect(_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
|
||||||
|
|
||||||
_bottomShadow = new ScrollableBoxShadow(this);
|
_bottomShadow.create(this);
|
||||||
bottomSkip = st::boxButtonPadding.top() + _save->height() + st::boxButtonPadding.bottom();
|
bottomSkip = st::boxButtonPadding.top() + _save->height() + st::boxButtonPadding.bottom();
|
||||||
} else if (_section == Section::ArchivedPart) {
|
} else if (_section == Section::ArchivedPart) {
|
||||||
_aboutHeight = st::stickersReorderPadding.top() + _about.countHeight(_aboutWidth) + st::stickersReorderPadding.bottom();
|
_aboutHeight = st::stickersReorderPadding.top() + _about.countHeight(_aboutWidth) + st::stickersReorderPadding.bottom();
|
||||||
_topShadow = new PlainShadow(this, st::contactsAboutShadow);
|
_topShadow.create(this, st::contactsAboutShadow);
|
||||||
|
|
||||||
_save = new BoxButton(this, lang(lng_box_ok), st::defaultBoxButton);
|
_save.create(this, lang(lng_box_ok), st::defaultBoxButton);
|
||||||
connect(_save, SIGNAL(clicked()), this, SLOT(onClose()));
|
connect(_save, SIGNAL(clicked()), this, SLOT(onClose()));
|
||||||
} else if (_section == Section::Archived) {
|
} else if (_section == Section::Archived) {
|
||||||
_aboutHeight = st::stickersReorderPadding.top() + _about.countHeight(_aboutWidth) + st::stickersReorderPadding.bottom();
|
_aboutHeight = st::stickersReorderPadding.top() + _about.countHeight(_aboutWidth) + st::stickersReorderPadding.bottom();
|
||||||
_topShadow = new PlainShadow(this, st::contactsAboutShadow);
|
_topShadow.create(this, st::contactsAboutShadow);
|
||||||
}
|
}
|
||||||
ItemListBox::init(_inner, bottomSkip, st::boxTitleHeight + _aboutHeight);
|
ItemListBox::init(_inner, bottomSkip, st::boxTitleHeight + _aboutHeight);
|
||||||
setMaxHeight(snap(countHeight(), int32(st::sessionsHeight), int32(st::boxMaxListHeight)));
|
setMaxHeight(snap(countHeight(), int32(st::sessionsHeight), int32(st::boxMaxListHeight)));
|
||||||
|
|
|
@ -24,6 +24,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "core/vector_of_moveable.h"
|
#include "core/vector_of_moveable.h"
|
||||||
|
|
||||||
class ConfirmBox;
|
class ConfirmBox;
|
||||||
|
namespace Ui {
|
||||||
|
class PlainShadow;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
class StickerSetInner : public ScrolledWidget, public RPCSender, private base::Subscriber {
|
class StickerSetInner : public ScrolledWidget, public RPCSender, private base::Subscriber {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -188,7 +191,7 @@ private:
|
||||||
ChildWidget<BoxButton> _cancel = { nullptr };
|
ChildWidget<BoxButton> _cancel = { nullptr };
|
||||||
OrderedSet<mtpRequestId> _disenableRequests;
|
OrderedSet<mtpRequestId> _disenableRequests;
|
||||||
mtpRequestId _reorderRequest = 0;
|
mtpRequestId _reorderRequest = 0;
|
||||||
ChildWidget<PlainShadow> _topShadow = { nullptr };
|
ChildWidget<Ui::PlainShadow> _topShadow = { nullptr };
|
||||||
ChildWidget<ScrollableBoxShadow> _bottomShadow = { nullptr };
|
ChildWidget<ScrollableBoxShadow> _bottomShadow = { nullptr };
|
||||||
|
|
||||||
QTimer _scrollTimer;
|
QTimer _scrollTimer;
|
||||||
|
|
|
@ -50,7 +50,7 @@ bool ClickHandler::setActive(const ClickHandlerPtr &p, ClickHandlerHost *host) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (p) {
|
if (p) {
|
||||||
_active.makeIfNull();
|
_active.createIfNull();
|
||||||
*_active = p;
|
*_active = p;
|
||||||
if ((_activeHost = host)) {
|
if ((_activeHost = host)) {
|
||||||
bool emitClickHandlerActiveChanged = (!_pressed || !*_pressed || *_pressed == *_active);
|
bool emitClickHandlerActiveChanged = (!_pressed || !*_pressed || *_pressed == *_active);
|
||||||
|
|
|
@ -93,7 +93,7 @@ public:
|
||||||
if (!_active || !*_active) {
|
if (!_active || !*_active) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_pressed.makeIfNull();
|
_pressed.createIfNull();
|
||||||
*_pressed = *_active;
|
*_pressed = *_active;
|
||||||
if ((_pressedHost = _activeHost)) {
|
if ((_pressedHost = _activeHost)) {
|
||||||
_pressedHost->clickHandlerPressedChanged(*_pressed, true);
|
_pressedHost->clickHandlerPressedChanged(*_pressed, true);
|
||||||
|
|
|
@ -189,7 +189,10 @@ public:
|
||||||
std::swap(_p, other._p);
|
std::swap(_p, other._p);
|
||||||
}
|
}
|
||||||
~unique_ptr() noexcept {
|
~unique_ptr() noexcept {
|
||||||
delete _p;
|
if (_p) {
|
||||||
|
delete _p;
|
||||||
|
_p = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
T &operator*() const {
|
T &operator*() const {
|
||||||
|
|
|
@ -450,15 +450,8 @@ public:
|
||||||
NeverFreedPointer(const NeverFreedPointer<T> &other) = delete;
|
NeverFreedPointer(const NeverFreedPointer<T> &other) = delete;
|
||||||
NeverFreedPointer &operator=(const NeverFreedPointer<T> &other) = delete;
|
NeverFreedPointer &operator=(const NeverFreedPointer<T> &other) = delete;
|
||||||
|
|
||||||
template <typename U>
|
|
||||||
void createIfNull(U creator) {
|
|
||||||
if (isNull()) {
|
|
||||||
reset(creator());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
void makeIfNull(Args&&... args) {
|
void createIfNull(Args&&... args) {
|
||||||
if (isNull()) {
|
if (isNull()) {
|
||||||
reset(new T(std_::forward<Args>(args)...));
|
reset(new T(std_::forward<Args>(args)...));
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ NeverFreedPointer<DataStructures> structures;
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
void registerAbstractStructure(AbstractStructure **p) {
|
void registerAbstractStructure(AbstractStructure **p) {
|
||||||
structures.makeIfNull();
|
structures.createIfNull();
|
||||||
structures->insert(p);
|
structures->insert(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -584,8 +584,11 @@ struct Data {
|
||||||
|
|
||||||
int32 DebugLoggingFlags = 0;
|
int32 DebugLoggingFlags = 0;
|
||||||
|
|
||||||
|
float64 RememberedSongVolume = kDefaultVolume;
|
||||||
float64 SongVolume = kDefaultVolume;
|
float64 SongVolume = kDefaultVolume;
|
||||||
|
base::Observable<void> SongVolumeChanged;
|
||||||
float64 VideoVolume = kDefaultVolume;
|
float64 VideoVolume = kDefaultVolume;
|
||||||
|
base::Observable<void> VideoVolumeChanged;
|
||||||
|
|
||||||
// config
|
// config
|
||||||
int32 ChatSizeMax = 200;
|
int32 ChatSizeMax = 200;
|
||||||
|
@ -694,8 +697,11 @@ DefineVar(Global, bool, ScreenIsLocked);
|
||||||
|
|
||||||
DefineVar(Global, int32, DebugLoggingFlags);
|
DefineVar(Global, int32, DebugLoggingFlags);
|
||||||
|
|
||||||
|
DefineVar(Global, float64, RememberedSongVolume);
|
||||||
DefineVar(Global, float64, SongVolume);
|
DefineVar(Global, float64, SongVolume);
|
||||||
|
DefineRefVar(Global, base::Observable<void>, SongVolumeChanged);
|
||||||
DefineVar(Global, float64, VideoVolume);
|
DefineVar(Global, float64, VideoVolume);
|
||||||
|
DefineRefVar(Global, base::Observable<void>, VideoVolumeChanged);
|
||||||
|
|
||||||
// config
|
// config
|
||||||
DefineVar(Global, int32, ChatSizeMax);
|
DefineVar(Global, int32, ChatSizeMax);
|
||||||
|
|
|
@ -252,8 +252,6 @@ bool started();
|
||||||
void start();
|
void start();
|
||||||
void finish();
|
void finish();
|
||||||
|
|
||||||
constexpr float64 kDefaultVolume = 0.9;
|
|
||||||
|
|
||||||
DeclareReadOnlyVar(uint64, LaunchId);
|
DeclareReadOnlyVar(uint64, LaunchId);
|
||||||
DeclareRefVar(SingleDelayedCall, HandleHistoryUpdate);
|
DeclareRefVar(SingleDelayedCall, HandleHistoryUpdate);
|
||||||
DeclareRefVar(SingleDelayedCall, HandleUnreadCounterUpdate);
|
DeclareRefVar(SingleDelayedCall, HandleUnreadCounterUpdate);
|
||||||
|
@ -273,8 +271,13 @@ DeclareVar(bool, ScreenIsLocked);
|
||||||
|
|
||||||
DeclareVar(int32, DebugLoggingFlags);
|
DeclareVar(int32, DebugLoggingFlags);
|
||||||
|
|
||||||
|
constexpr float64 kDefaultVolume = 0.9;
|
||||||
|
|
||||||
|
DeclareVar(float64, RememberedSongVolume);
|
||||||
DeclareVar(float64, SongVolume);
|
DeclareVar(float64, SongVolume);
|
||||||
|
DeclareRefVar(base::Observable<void>, SongVolumeChanged);
|
||||||
DeclareVar(float64, VideoVolume);
|
DeclareVar(float64, VideoVolume);
|
||||||
|
DeclareRefVar(base::Observable<void>, VideoVolumeChanged);
|
||||||
|
|
||||||
// config
|
// config
|
||||||
DeclareVar(int32, ChatSizeMax);
|
DeclareVar(int32, ChatSizeMax);
|
||||||
|
|
|
@ -25,9 +25,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
#include "playerwidget.h"
|
|
||||||
#include "media/media_audio.h"
|
#include "media/media_audio.h"
|
||||||
#include "media/media_clip_reader.h"
|
#include "media/media_clip_reader.h"
|
||||||
|
#include "media/player/media_player_instance.h"
|
||||||
#include "boxes/confirmbox.h"
|
#include "boxes/confirmbox.h"
|
||||||
#include "boxes/addcontactbox.h"
|
#include "boxes/addcontactbox.h"
|
||||||
#include "core/click_handler_types.h"
|
#include "core/click_handler_types.h"
|
||||||
|
@ -1463,8 +1463,8 @@ bool HistoryDocument::updateStatusText() const {
|
||||||
showPause = (playbackState.state == AudioPlayerPlaying || playbackState.state == AudioPlayerResuming || playbackState.state == AudioPlayerStarting);
|
showPause = (playbackState.state == AudioPlayerPlaying || playbackState.state == AudioPlayerResuming || playbackState.state == AudioPlayerStarting);
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
if (!showPause && (playing == AudioMsgId(_data, _parent->fullId())) && App::main() && App::main()->player()->seekingSong(playing)) {
|
if (!showPause && (playing == AudioMsgId(_data, _parent->fullId()))) {
|
||||||
showPause = true;
|
showPause = (Media::Player::exists() && Media::Player::instance()->isSeeking());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "window/top_bar_widget.h"
|
#include "window/top_bar_widget.h"
|
||||||
#include "window/chat_background.h"
|
#include "window/chat_background.h"
|
||||||
#include "observer_peer.h"
|
#include "observer_peer.h"
|
||||||
#include "playerwidget.h"
|
|
||||||
#include "core/qthelp_regex.h"
|
#include "core/qthelp_regex.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -3124,7 +3123,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
|
||||||
_attachDragDocument->hide();
|
_attachDragDocument->hide();
|
||||||
_attachDragPhoto->hide();
|
_attachDragPhoto->hide();
|
||||||
|
|
||||||
_topShadow.hide();
|
_topShadow->hide();
|
||||||
|
|
||||||
connect(_attachDragDocument, SIGNAL(dropped(const QMimeData*)), this, SLOT(onDocumentDrop(const QMimeData*)));
|
connect(_attachDragDocument, SIGNAL(dropped(const QMimeData*)), this, SLOT(onDocumentDrop(const QMimeData*)));
|
||||||
connect(_attachDragPhoto, SIGNAL(dropped(const QMimeData*)), this, SLOT(onPhotoDrop(const QMimeData*)));
|
connect(_attachDragPhoto, SIGNAL(dropped(const QMimeData*)), this, SLOT(onPhotoDrop(const QMimeData*)));
|
||||||
|
@ -4474,7 +4473,7 @@ bool HistoryWidget::canWriteMessage() const {
|
||||||
|
|
||||||
void HistoryWidget::updateControlsVisibility() {
|
void HistoryWidget::updateControlsVisibility() {
|
||||||
if (!_a_show.animating()) {
|
if (!_a_show.animating()) {
|
||||||
_topShadow.setVisible(_peer ? true : false);
|
_topShadow->setVisible(_peer ? true : false);
|
||||||
}
|
}
|
||||||
updateToEndVisibility();
|
updateToEndVisibility();
|
||||||
if (!_history || _a_show.animating()) {
|
if (!_history || _a_show.animating()) {
|
||||||
|
@ -4501,15 +4500,15 @@ void HistoryWidget::updateControlsVisibility() {
|
||||||
_attachType->hide();
|
_attachType->hide();
|
||||||
_emojiPan->hide();
|
_emojiPan->hide();
|
||||||
if (_pinnedBar) {
|
if (_pinnedBar) {
|
||||||
_pinnedBar->cancel.hide();
|
_pinnedBar->cancel->hide();
|
||||||
_pinnedBar->shadow.hide();
|
_pinnedBar->shadow->hide();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_pinnedBar) {
|
if (_pinnedBar) {
|
||||||
_pinnedBar->cancel.show();
|
_pinnedBar->cancel->show();
|
||||||
_pinnedBar->shadow.show();
|
_pinnedBar->shadow->show();
|
||||||
}
|
}
|
||||||
if (_firstLoadRequest && !_scroll.isHidden()) {
|
if (_firstLoadRequest && !_scroll.isHidden()) {
|
||||||
_scroll.hide();
|
_scroll.hide();
|
||||||
|
@ -5431,11 +5430,11 @@ void HistoryWidget::showAnimated(Window::SlideDirection direction, const Window:
|
||||||
|
|
||||||
_cacheUnder = params.oldContentCache;
|
_cacheUnder = params.oldContentCache;
|
||||||
show();
|
show();
|
||||||
_topShadow.setVisible(params.withTopBarShadow ? false : true);
|
_topShadow->setVisible(params.withTopBarShadow ? false : true);
|
||||||
_historyToEnd->finishAnimation();
|
_historyToEnd->finishAnimation();
|
||||||
_cacheOver = App::main()->grabForShowAnimation(params);
|
_cacheOver = App::main()->grabForShowAnimation(params);
|
||||||
App::main()->topBar()->startAnim();
|
App::main()->topBar()->startAnim();
|
||||||
_topShadow.setVisible(params.withTopBarShadow ? true : false);
|
_topShadow->setVisible(params.withTopBarShadow ? true : false);
|
||||||
|
|
||||||
_scroll.hide();
|
_scroll.hide();
|
||||||
_kbScroll.hide();
|
_kbScroll.hide();
|
||||||
|
@ -5458,8 +5457,8 @@ void HistoryWidget::showAnimated(Window::SlideDirection direction, const Window:
|
||||||
_joinChannel.hide();
|
_joinChannel.hide();
|
||||||
_muteUnmute.hide();
|
_muteUnmute.hide();
|
||||||
if (_pinnedBar) {
|
if (_pinnedBar) {
|
||||||
_pinnedBar->shadow.hide();
|
_pinnedBar->shadow->hide();
|
||||||
_pinnedBar->cancel.hide();
|
_pinnedBar->cancel->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
int delta = st::slideShift;
|
int delta = st::slideShift;
|
||||||
|
@ -5484,7 +5483,7 @@ void HistoryWidget::step_show(float64 ms, bool timer) {
|
||||||
float64 dt = ms / st::slideDuration;
|
float64 dt = ms / st::slideDuration;
|
||||||
if (dt >= 1) {
|
if (dt >= 1) {
|
||||||
_a_show.stop();
|
_a_show.stop();
|
||||||
_topShadow.setVisible(_peer ? true : false);
|
_topShadow->setVisible(_peer ? true : false);
|
||||||
_historyToEnd->finishAnimation();
|
_historyToEnd->finishAnimation();
|
||||||
|
|
||||||
a_coordUnder.finish();
|
a_coordUnder.finish();
|
||||||
|
@ -5525,7 +5524,7 @@ void HistoryWidget::doneShow() {
|
||||||
void HistoryWidget::animStop() {
|
void HistoryWidget::animStop() {
|
||||||
if (!_a_show.animating()) return;
|
if (!_a_show.animating()) return;
|
||||||
_a_show.stop();
|
_a_show.stop();
|
||||||
_topShadow.setVisible(_peer ? true : false);
|
_topShadow->setVisible(_peer ? true : false);
|
||||||
_historyToEnd->finishAnimation();
|
_historyToEnd->finishAnimation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6916,6 +6915,17 @@ void HistoryWidget::peerMessagesUpdated() {
|
||||||
if (_list) peerMessagesUpdated(_peer->id);
|
if (_list) peerMessagesUpdated(_peer->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HistoryWidget::grapWithoutTopBarShadow() {
|
||||||
|
grabStart();
|
||||||
|
_topShadow->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistoryWidget::grabFinish() {
|
||||||
|
_inGrab = false;
|
||||||
|
resizeEvent(0);
|
||||||
|
_topShadow->show();
|
||||||
|
}
|
||||||
|
|
||||||
bool HistoryWidget::isItemVisible(HistoryItem *item) {
|
bool HistoryWidget::isItemVisible(HistoryItem *item) {
|
||||||
if (isHidden() || _a_show.animating() || !_list) {
|
if (isHidden() || _a_show.animating() || !_list) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -6993,8 +7003,8 @@ void HistoryWidget::resizeEvent(QResizeEvent *e) {
|
||||||
_reportSpamPanel.move(0, st::replyHeight);
|
_reportSpamPanel.move(0, st::replyHeight);
|
||||||
_fieldAutocomplete->setBoundings(_scroll.geometry());
|
_fieldAutocomplete->setBoundings(_scroll.geometry());
|
||||||
}
|
}
|
||||||
_pinnedBar->cancel.move(width() - _pinnedBar->cancel.width(), 0);
|
_pinnedBar->cancel->move(width() - _pinnedBar->cancel->width(), 0);
|
||||||
_pinnedBar->shadow.setGeometry(0, st::replyHeight, width(), st::lineWidth);
|
_pinnedBar->shadow->setGeometry(0, st::replyHeight, width(), st::lineWidth);
|
||||||
} else if (_scroll.y() != 0) {
|
} else if (_scroll.y() != 0) {
|
||||||
_scroll.move(0, 0);
|
_scroll.move(0, 0);
|
||||||
_reportSpamPanel.move(0, 0);
|
_reportSpamPanel.move(0, 0);
|
||||||
|
@ -7029,8 +7039,8 @@ void HistoryWidget::resizeEvent(QResizeEvent *e) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_topShadow.resize(width() - ((!Adaptive::OneColumn() && !_inGrab) ? st::lineWidth : 0), st::lineWidth);
|
_topShadow->resize(width() - ((!Adaptive::OneColumn() && !_inGrab) ? st::lineWidth : 0), st::lineWidth);
|
||||||
_topShadow.moveToLeft((!Adaptive::OneColumn() && !_inGrab) ? st::lineWidth : 0, 0);
|
_topShadow->moveToLeft((!Adaptive::OneColumn() && !_inGrab) ? st::lineWidth : 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::itemRemoved(HistoryItem *item) {
|
void HistoryWidget::itemRemoved(HistoryItem *item) {
|
||||||
|
@ -7532,7 +7542,6 @@ void HistoryWidget::onInlineResultSend(InlineBots::Result *result, UserData *bot
|
||||||
|
|
||||||
HistoryWidget::PinnedBar::PinnedBar(MsgId msgId, HistoryWidget *parent)
|
HistoryWidget::PinnedBar::PinnedBar(MsgId msgId, HistoryWidget *parent)
|
||||||
: msgId(msgId)
|
: msgId(msgId)
|
||||||
, msg(0)
|
|
||||||
, cancel(parent, st::replyCancel)
|
, cancel(parent, st::replyCancel)
|
||||||
, shadow(parent, st::shadowColor) {
|
, shadow(parent, st::shadowColor) {
|
||||||
}
|
}
|
||||||
|
@ -7582,15 +7591,15 @@ bool HistoryWidget::pinnedMsgVisibilityUpdated() {
|
||||||
if (!_pinnedBar) {
|
if (!_pinnedBar) {
|
||||||
_pinnedBar = new PinnedBar(pinnedMsgId, this);
|
_pinnedBar = new PinnedBar(pinnedMsgId, this);
|
||||||
if (_a_show.animating()) {
|
if (_a_show.animating()) {
|
||||||
_pinnedBar->cancel.hide();
|
_pinnedBar->cancel->hide();
|
||||||
_pinnedBar->shadow.hide();
|
_pinnedBar->shadow->hide();
|
||||||
} else {
|
} else {
|
||||||
_pinnedBar->cancel.show();
|
_pinnedBar->cancel->show();
|
||||||
_pinnedBar->shadow.show();
|
_pinnedBar->shadow->show();
|
||||||
}
|
}
|
||||||
connect(&_pinnedBar->cancel, SIGNAL(clicked()), this, SLOT(onPinnedHide()));
|
connect(_pinnedBar->cancel, SIGNAL(clicked()), this, SLOT(onPinnedHide()));
|
||||||
_reportSpamPanel.raise();
|
_reportSpamPanel.raise();
|
||||||
_topShadow.raise();
|
_topShadow->raise();
|
||||||
if (_membersDropdown) {
|
if (_membersDropdown) {
|
||||||
_membersDropdown->raise();
|
_membersDropdown->raise();
|
||||||
}
|
}
|
||||||
|
@ -8676,11 +8685,11 @@ void HistoryWidget::drawPinnedBar(Painter &p) {
|
||||||
p.drawText(left, st::msgReplyPadding.top() + st::msgServiceNameFont->ascent, lang(lng_pinned_message));
|
p.drawText(left, st::msgReplyPadding.top() + st::msgServiceNameFont->ascent, lang(lng_pinned_message));
|
||||||
|
|
||||||
p.setPen((((_pinnedBar->msg->toHistoryMessage() && _pinnedBar->msg->toHistoryMessage()->emptyText()) || _pinnedBar->msg->serviceMsg()) ? st::msgInDateFg : st::msgColor)->p);
|
p.setPen((((_pinnedBar->msg->toHistoryMessage() && _pinnedBar->msg->toHistoryMessage()->emptyText()) || _pinnedBar->msg->serviceMsg()) ? st::msgInDateFg : st::msgColor)->p);
|
||||||
_pinnedBar->text.drawElided(p, left, st::msgReplyPadding.top() + st::msgServiceNameFont->height, width() - left - _pinnedBar->cancel.width() - st::msgReplyPadding.right());
|
_pinnedBar->text.drawElided(p, left, st::msgReplyPadding.top() + st::msgServiceNameFont->height, width() - left - _pinnedBar->cancel->width() - st::msgReplyPadding.right());
|
||||||
} else {
|
} else {
|
||||||
p.setFont(st::msgDateFont);
|
p.setFont(st::msgDateFont);
|
||||||
p.setPen(st::msgInDateFg);
|
p.setPen(st::msgInDateFg);
|
||||||
p.drawText(left, st::msgReplyPadding.top() + (st::msgReplyBarSize.height() - st::msgDateFont->height) / 2 + st::msgDateFont->ascent, st::msgDateFont->elided(lang(lng_profile_loading), width() - left - _pinnedBar->cancel.width() - st::msgReplyPadding.right()));
|
p.drawText(left, st::msgReplyPadding.top() + (st::msgReplyBarSize.height() - st::msgDateFont->height) / 2 + st::msgDateFont->ascent, st::msgDateFont->elided(lang(lng_profile_loading), width() - left - _pinnedBar->cancel->width() - st::msgReplyPadding.right()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8715,7 +8724,7 @@ void HistoryWidget::paintEvent(QPaintEvent *e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QRect fill(0, 0, width(), App::main()->height());
|
QRect fill(0, 0, width(), App::main()->height());
|
||||||
int fromy = (hasTopBar ? (-st::topBarHeight) : 0), x = 0, y = 0;
|
int fromy = App::main()->backgroundFromY(), x = 0, y = 0;
|
||||||
QPixmap cached = App::main()->cachedBackground(fill, x, y);
|
QPixmap cached = App::main()->cachedBackground(fill, x, y);
|
||||||
if (cached.isNull()) {
|
if (cached.isNull()) {
|
||||||
auto &pix = Window::chatBackground()->image();
|
auto &pix = Window::chatBackground()->image();
|
||||||
|
@ -8751,7 +8760,7 @@ void HistoryWidget::paintEvent(QPaintEvent *e) {
|
||||||
if (_recording) drawRecording(p);
|
if (_recording) drawRecording(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_pinnedBar && !_pinnedBar->cancel.isHidden()) {
|
if (_pinnedBar && !_pinnedBar->cancel->isHidden()) {
|
||||||
drawPinnedBar(p);
|
drawPinnedBar(p);
|
||||||
}
|
}
|
||||||
if (_scroll.isHidden()) {
|
if (_scroll.isHidden()) {
|
||||||
|
|
|
@ -38,6 +38,7 @@ class Result;
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class HistoryDownButton;
|
class HistoryDownButton;
|
||||||
class InnerDropdown;
|
class InnerDropdown;
|
||||||
|
class PlainShadow;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
class Dropdown;
|
class Dropdown;
|
||||||
|
@ -530,7 +531,6 @@ class HistoryWidget : public TWidget, public RPCSender, private base::Subscriber
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
HistoryWidget(QWidget *parent);
|
HistoryWidget(QWidget *parent);
|
||||||
|
|
||||||
void start();
|
void start();
|
||||||
|
@ -701,15 +701,8 @@ public:
|
||||||
_inGrab = true;
|
_inGrab = true;
|
||||||
resizeEvent(0);
|
resizeEvent(0);
|
||||||
}
|
}
|
||||||
void grapWithoutTopBarShadow() {
|
void grapWithoutTopBarShadow();
|
||||||
grabStart();
|
void grabFinish() override;
|
||||||
_topShadow.hide();
|
|
||||||
}
|
|
||||||
void grabFinish() override {
|
|
||||||
_inGrab = false;
|
|
||||||
resizeEvent(0);
|
|
||||||
_topShadow.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isItemVisible(HistoryItem *item);
|
bool isItemVisible(HistoryItem *item);
|
||||||
|
|
||||||
|
@ -902,8 +895,8 @@ private:
|
||||||
MsgId msgId = 0;
|
MsgId msgId = 0;
|
||||||
HistoryItem *msg = nullptr;
|
HistoryItem *msg = nullptr;
|
||||||
Text text;
|
Text text;
|
||||||
IconedButton cancel;
|
ChildWidget<IconedButton> cancel;
|
||||||
PlainShadow shadow;
|
ChildWidget<Ui::PlainShadow> shadow;
|
||||||
};
|
};
|
||||||
PinnedBar *_pinnedBar = nullptr;
|
PinnedBar *_pinnedBar = nullptr;
|
||||||
void updatePinnedBar(bool force = false);
|
void updatePinnedBar(bool force = false);
|
||||||
|
@ -1163,7 +1156,7 @@ private:
|
||||||
bool _saveDraftText = false;
|
bool _saveDraftText = false;
|
||||||
QTimer _saveDraftTimer, _saveCloudDraftTimer;
|
QTimer _saveDraftTimer, _saveCloudDraftTimer;
|
||||||
|
|
||||||
PlainShadow _topShadow;
|
ChildWidget<Ui::PlainShadow> _topShadow;
|
||||||
bool _inGrab = false;
|
bool _inGrab = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,13 +24,13 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "styles/style_overview.h"
|
#include "styles/style_overview.h"
|
||||||
#include "styles/style_history.h"
|
#include "styles/style_history.h"
|
||||||
#include "inline_bots/inline_bot_result.h"
|
#include "inline_bots/inline_bot_result.h"
|
||||||
|
#include "media/media_audio.h"
|
||||||
#include "media/media_clip_reader.h"
|
#include "media/media_clip_reader.h"
|
||||||
#include "media/player/media_player_instance.h"
|
#include "media/player/media_player_instance.h"
|
||||||
#include "history/history_location_manager.h"
|
#include "history/history_location_manager.h"
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
#include "playerwidget.h"
|
|
||||||
|
|
||||||
namespace InlineBots {
|
namespace InlineBots {
|
||||||
namespace Layout {
|
namespace Layout {
|
||||||
|
|
|
@ -209,7 +209,7 @@ const DocumentItems *documentItems() {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
void regDocumentItem(DocumentData *document, ItemBase *item) {
|
void regDocumentItem(DocumentData *document, ItemBase *item) {
|
||||||
documentItemsMap.makeIfNull();
|
documentItemsMap.createIfNull();
|
||||||
(*documentItemsMap)[document].insert(item);
|
(*documentItemsMap)[document].insert(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -232,7 +232,7 @@ bool Result::onChoose(Layout::ItemBase *layout) {
|
||||||
} else if (_document->loading()) {
|
} else if (_document->loading()) {
|
||||||
_document->cancel();
|
_document->cancel();
|
||||||
} else {
|
} else {
|
||||||
DocumentOpenClickHandler::doOpen(_document, ActionOnLoadNone);
|
DocumentOpenClickHandler::doOpen(_document, nullptr, ActionOnLoadNone);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "fileuploader.h"
|
#include "fileuploader.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "ui/filedialog.h"
|
#include "ui/filedialog.h"
|
||||||
#include "playerwidget.h"
|
|
||||||
#include "boxes/addcontactbox.h"
|
#include "boxes/addcontactbox.h"
|
||||||
#include "boxes/confirmbox.h"
|
#include "boxes/confirmbox.h"
|
||||||
#include "media/media_audio.h"
|
#include "media/media_audio.h"
|
||||||
|
|
|
@ -175,29 +175,22 @@ void TaskQueueWorker::onTaskAdded() {
|
||||||
FileLoadTask::FileLoadTask(const QString &filepath, PrepareMediaType type, const FileLoadTo &to, FileLoadForceConfirmType confirm) : _id(rand_value<uint64>())
|
FileLoadTask::FileLoadTask(const QString &filepath, PrepareMediaType type, const FileLoadTo &to, FileLoadForceConfirmType confirm) : _id(rand_value<uint64>())
|
||||||
, _to(to)
|
, _to(to)
|
||||||
, _filepath(filepath)
|
, _filepath(filepath)
|
||||||
, _duration(0)
|
|
||||||
, _type(type)
|
, _type(type)
|
||||||
, _confirm(confirm)
|
, _confirm(confirm) {
|
||||||
, _result(0) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FileLoadTask::FileLoadTask(const QByteArray &content, PrepareMediaType type, const FileLoadTo &to) : _id(rand_value<uint64>())
|
FileLoadTask::FileLoadTask(const QByteArray &content, PrepareMediaType type, const FileLoadTo &to) : _id(rand_value<uint64>())
|
||||||
, _to(to)
|
, _to(to)
|
||||||
, _content(content)
|
, _content(content)
|
||||||
, _duration(0)
|
, _type(type) {
|
||||||
, _type(type)
|
|
||||||
, _confirm(FileLoadNoForceConfirm)
|
|
||||||
, _result(0) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FileLoadTask::FileLoadTask(const QImage &image, PrepareMediaType type, const FileLoadTo &to, FileLoadForceConfirmType confirm, const QString &originalText) : _id(rand_value<uint64>())
|
FileLoadTask::FileLoadTask(const QImage &image, PrepareMediaType type, const FileLoadTo &to, FileLoadForceConfirmType confirm, const QString &originalText) : _id(rand_value<uint64>())
|
||||||
, _to(to)
|
, _to(to)
|
||||||
, _image(image)
|
, _image(image)
|
||||||
, _duration(0)
|
|
||||||
, _type(type)
|
, _type(type)
|
||||||
, _confirm(confirm)
|
, _confirm(confirm)
|
||||||
, _originalText(originalText)
|
, _originalText(originalText) {
|
||||||
, _result(0) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FileLoadTask::FileLoadTask(const QByteArray &voice, int32 duration, const VoiceWaveform &waveform, const FileLoadTo &to) : _id(rand_value<uint64>())
|
FileLoadTask::FileLoadTask(const QByteArray &voice, int32 duration, const VoiceWaveform &waveform, const FileLoadTo &to) : _id(rand_value<uint64>())
|
||||||
|
@ -205,9 +198,7 @@ FileLoadTask::FileLoadTask(const QByteArray &voice, int32 duration, const VoiceW
|
||||||
, _content(voice)
|
, _content(voice)
|
||||||
, _duration(duration)
|
, _duration(duration)
|
||||||
, _waveform(waveform)
|
, _waveform(waveform)
|
||||||
, _type(PrepareAudio)
|
, _type(PrepareAudio) {
|
||||||
, _confirm(FileLoadNoForceConfirm)
|
|
||||||
, _result(0) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileLoadTask::process() {
|
void FileLoadTask::process() {
|
||||||
|
|
|
@ -263,10 +263,10 @@ protected:
|
||||||
QString _filepath;
|
QString _filepath;
|
||||||
QImage _image;
|
QImage _image;
|
||||||
QByteArray _content;
|
QByteArray _content;
|
||||||
int32 _duration;
|
int32 _duration = 0;
|
||||||
VoiceWaveform _waveform;
|
VoiceWaveform _waveform;
|
||||||
PrepareMediaType _type;
|
PrepareMediaType _type;
|
||||||
FileLoadForceConfirmType _confirm;
|
FileLoadForceConfirmType _confirm = FileLoadNoForceConfirm;
|
||||||
QString _originalText;
|
QString _originalText;
|
||||||
|
|
||||||
FileLoadResultPtr _result;
|
FileLoadResultPtr _result;
|
||||||
|
|
|
@ -24,6 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "styles/style_dialogs.h"
|
#include "styles/style_dialogs.h"
|
||||||
#include "ui/buttons/peer_avatar_button.h"
|
#include "ui/buttons/peer_avatar_button.h"
|
||||||
#include "ui/buttons/round_button.h"
|
#include "ui/buttons/round_button.h"
|
||||||
|
#include "ui/widgets/shadow.h"
|
||||||
#include "window/section_memento.h"
|
#include "window/section_memento.h"
|
||||||
#include "window/section_widget.h"
|
#include "window/section_widget.h"
|
||||||
#include "window/top_bar_widget.h"
|
#include "window/top_bar_widget.h"
|
||||||
|
@ -34,7 +35,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "dialogswidget.h"
|
#include "dialogswidget.h"
|
||||||
#include "historywidget.h"
|
#include "historywidget.h"
|
||||||
#include "overviewwidget.h"
|
#include "overviewwidget.h"
|
||||||
#include "playerwidget.h"
|
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
#include "boxes/addcontactbox.h"
|
#include "boxes/addcontactbox.h"
|
||||||
#include "fileuploader.h"
|
#include "fileuploader.h"
|
||||||
|
@ -50,11 +50,14 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
#include "shortcuts.h"
|
#include "shortcuts.h"
|
||||||
#include "media/media_audio.h"
|
#include "media/media_audio.h"
|
||||||
|
#include "media/player/media_player_panel.h"
|
||||||
#include "media/player/media_player_widget.h"
|
#include "media/player/media_player_widget.h"
|
||||||
|
#include "media/player/media_player_volume_controller.h"
|
||||||
#include "media/player/media_player_instance.h"
|
#include "media/player/media_player_instance.h"
|
||||||
#include "core/qthelp_regex.h"
|
#include "core/qthelp_regex.h"
|
||||||
#include "core/qthelp_url.h"
|
#include "core/qthelp_url.h"
|
||||||
#include "window/chat_background.h"
|
#include "window/chat_background.h"
|
||||||
|
#include "window/player_wrap_widget.h"
|
||||||
|
|
||||||
StackItemSection::StackItemSection(std_::unique_ptr<Window::SectionMemento> &&memento) : StackItem(nullptr)
|
StackItemSection::StackItemSection(std_::unique_ptr<Window::SectionMemento> &&memento) : StackItem(nullptr)
|
||||||
, _memento(std_::move(memento)) {
|
, _memento(std_::move(memento)) {
|
||||||
|
@ -63,15 +66,12 @@ StackItemSection::StackItemSection(std_::unique_ptr<Window::SectionMemento> &&me
|
||||||
StackItemSection::~StackItemSection() {
|
StackItemSection::~StackItemSection() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "boxes/confirmphonebox.h"
|
|
||||||
|
|
||||||
MainWidget::MainWidget(MainWindow *window) : TWidget(window)
|
MainWidget::MainWidget(MainWindow *window) : TWidget(window)
|
||||||
, _a_show(animation(this, &MainWidget::step_show))
|
, _a_show(animation(this, &MainWidget::step_show))
|
||||||
, _dialogsWidth(st::dialogsWidthMin)
|
, _dialogsWidth(st::dialogsWidthMin)
|
||||||
, _sideShadow(this, st::shadowColor)
|
, _sideShadow(this, st::shadowColor)
|
||||||
, _dialogs(this)
|
, _dialogs(this)
|
||||||
, _history(this)
|
, _history(this)
|
||||||
, _player(this)
|
|
||||||
, _topBar(this)
|
, _topBar(this)
|
||||||
, _mediaType(this)
|
, _mediaType(this)
|
||||||
, _api(new ApiWrap(this)) {
|
, _api(new ApiWrap(this)) {
|
||||||
|
@ -131,8 +131,6 @@ MainWidget::MainWidget(MainWindow *window) : TWidget(window)
|
||||||
App::wnd()->getTitle()->updateControlsVisibility();
|
App::wnd()->getTitle()->updateControlsVisibility();
|
||||||
_topBar->hide();
|
_topBar->hide();
|
||||||
|
|
||||||
_player->hidePlayer();
|
|
||||||
|
|
||||||
orderWidgets();
|
orderWidgets();
|
||||||
|
|
||||||
MTP::setGlobalFailHandler(rpcFail(&MainWidget::updateFail));
|
MTP::setGlobalFailHandler(rpcFail(&MainWidget::updateFail));
|
||||||
|
@ -1344,7 +1342,6 @@ void MainWidget::overviewPreloaded(PeerData *peer, const MTPmessages_Messages &r
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) {
|
void MainWidget::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) {
|
||||||
if (!_player->isHidden()) _player->mediaOverviewUpdated(peer, type);
|
|
||||||
if (_overview && (_overview->peer() == peer || _overview->peer()->migrateFrom() == peer)) {
|
if (_overview && (_overview->peer() == peer || _overview->peer()->migrateFrom() == peer)) {
|
||||||
_overview->mediaOverviewUpdated(peer, type);
|
_overview->mediaOverviewUpdated(peer, type);
|
||||||
|
|
||||||
|
@ -1581,24 +1578,8 @@ void MainWidget::handleAudioUpdate(const AudioMsgId &audioId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (playing == audioId && audioId.type() == AudioMsgId::Type::Song) {
|
if (playing == audioId && audioId.type() == AudioMsgId::Type::Song) {
|
||||||
if (!_mediaPlayer && Media::Player::exists()) {
|
if (!_playerPanel && !_player && Media::Player::exists()) {
|
||||||
_mediaPlayer.create(this);
|
createPlayer();
|
||||||
updateMediaPlayerPosition();
|
|
||||||
orderWidgets();
|
|
||||||
Media::Player::instance()->createdNotifier().notify(Media::Player::CreatedEvent(_mediaPlayer), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
_player->updateState(playing, playbackState);
|
|
||||||
|
|
||||||
if (!(playbackState.state & AudioPlayerStoppedMask) && playbackState.state != AudioPlayerFinishing) {
|
|
||||||
if (!_player->isOpened()) {
|
|
||||||
_player->openPlayer();
|
|
||||||
if (_player->isHidden() && !_a_show.animating()) {
|
|
||||||
_player->showPlayer();
|
|
||||||
_playerHeight = _contentScrollAddToY = _player->height();
|
|
||||||
resizeEvent(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1612,18 +1593,62 @@ void MainWidget::handleAudioUpdate(const AudioMsgId &audioId) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::closePlayer() {
|
void MainWidget::switchToPanelPlayer() {
|
||||||
if (_player->isOpened()) {
|
_player->slideUp();
|
||||||
_player->closePlayer();
|
_playerVolume.destroyDelayed();
|
||||||
if (!_player->isHidden() && !_a_show.animating()) {
|
if (!_playerPanel) {
|
||||||
_player->hidePlayer();
|
_playerPanel.create(this, Media::Player::Panel::Layout::Full);
|
||||||
_contentScrollAddToY = -_player->height();
|
_playerPanel->setPinCallback([this] { switchToFixedPlayer(); });
|
||||||
_playerHeight = 0;
|
updateMediaPlayerPosition();
|
||||||
resizeEvent(0);
|
orderWidgets();
|
||||||
|
Media::Player::instance()->createdNotifier().notify(Media::Player::PanelEvent(_playerPanel), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWidget::switchToFixedPlayer() {
|
||||||
|
_playerPanel.destroyDelayed();
|
||||||
|
if (!_player) {
|
||||||
|
createPlayer();
|
||||||
|
} else {
|
||||||
|
_player->slideDown();
|
||||||
|
if (!_playerVolume) {
|
||||||
|
_playerVolume.create(this);
|
||||||
|
_player->entity()->volumeWidgetCreated(_playerVolume);
|
||||||
|
updateMediaPlayerPosition();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWidget::createPlayer() {
|
||||||
|
_player.create(this, [this] { playerHeightUpdated(); });
|
||||||
|
_player->entity()->setCloseCallback([this] { switchToPanelPlayer(); });
|
||||||
|
_playerVolume.create(this);
|
||||||
|
_player->entity()->volumeWidgetCreated(_playerVolume);
|
||||||
|
orderWidgets();
|
||||||
|
if (_a_show.animating()) {
|
||||||
|
_player->showFast();
|
||||||
|
_player->hide();
|
||||||
|
} else {
|
||||||
|
_player->hideFast();
|
||||||
|
_player->slideDown();
|
||||||
|
_playerHeight = _contentScrollAddToY = _player->contentHeight();
|
||||||
|
updateControlsGeometry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWidget::playerHeightUpdated() {
|
||||||
|
auto playerHeight = _player->contentHeight();
|
||||||
|
if (playerHeight != _playerHeight) {
|
||||||
|
_contentScrollAddToY += playerHeight - _playerHeight;
|
||||||
|
_playerHeight = playerHeight;
|
||||||
|
updateControlsGeometry();
|
||||||
|
}
|
||||||
|
if (_playerPanel && !_playerHeight && _player->isHidden()) {
|
||||||
|
_playerVolume.destroyDelayed();
|
||||||
|
_player.destroyDelayed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MainWidget::documentLoadProgress(FileLoader *loader) {
|
void MainWidget::documentLoadProgress(FileLoader *loader) {
|
||||||
if (auto mtpLoader = loader ? loader->mtpLoader() : nullptr) {
|
if (auto mtpLoader = loader ? loader->mtpLoader() : nullptr) {
|
||||||
documentLoadProgress(App::document(mtpLoader->objId()));
|
documentLoadProgress(App::document(mtpLoader->objId()));
|
||||||
|
@ -1645,13 +1670,6 @@ void MainWidget::documentLoadProgress(DocumentData *document) {
|
||||||
App::wnd()->documentUpdated(document);
|
App::wnd()->documentUpdated(document);
|
||||||
|
|
||||||
if (!document->loaded() && document->song()) {
|
if (!document->loaded() && document->song()) {
|
||||||
if (audioPlayer() && document->loading()) {
|
|
||||||
AudioMsgId playing;
|
|
||||||
auto playbackState = audioPlayer()->currentState(&playing, AudioMsgId::Type::Song);
|
|
||||||
if (playing.audio() == document && !_player->isHidden()) {
|
|
||||||
_player->updateState(playing, playbackState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Media::Player::exists()) {
|
if (Media::Player::exists()) {
|
||||||
Media::Player::instance()->documentLoadProgress(document);
|
Media::Player::instance()->documentLoadProgress(document);
|
||||||
}
|
}
|
||||||
|
@ -2314,6 +2332,9 @@ Window::SectionSlideParams MainWidget::prepareShowAnimation(bool willHaveTopBarS
|
||||||
result.withTopBarShadow = false;
|
result.withTopBarShadow = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_player) {
|
||||||
|
_player->hideShadow();
|
||||||
|
}
|
||||||
if (selectingPeer() && Adaptive::OneColumn()) {
|
if (selectingPeer() && Adaptive::OneColumn()) {
|
||||||
result.oldContentCache = myGrab(this, QRect(0, _playerHeight, _dialogsWidth, height() - _playerHeight));
|
result.oldContentCache = myGrab(this, QRect(0, _playerHeight, _dialogsWidth, height() - _playerHeight));
|
||||||
} else if (_wideSection) {
|
} else if (_wideSection) {
|
||||||
|
@ -2329,13 +2350,16 @@ Window::SectionSlideParams MainWidget::prepareShowAnimation(bool willHaveTopBarS
|
||||||
if (Adaptive::OneColumn()) {
|
if (Adaptive::OneColumn()) {
|
||||||
result.oldContentCache = myGrab(this, QRect(0, _playerHeight, _dialogsWidth, height() - _playerHeight));
|
result.oldContentCache = myGrab(this, QRect(0, _playerHeight, _dialogsWidth, height() - _playerHeight));
|
||||||
} else {
|
} else {
|
||||||
_sideShadow.hide();
|
_sideShadow->hide();
|
||||||
result.oldContentCache = myGrab(this, QRect(_dialogsWidth, _playerHeight, width() - _dialogsWidth, height() - _playerHeight));
|
result.oldContentCache = myGrab(this, QRect(_dialogsWidth, _playerHeight, width() - _dialogsWidth, height() - _playerHeight));
|
||||||
_sideShadow.show();
|
_sideShadow->show();
|
||||||
}
|
}
|
||||||
if (_overview) _overview->grabFinish();
|
if (_overview) _overview->grabFinish();
|
||||||
_history->grabFinish();
|
_history->grabFinish();
|
||||||
}
|
}
|
||||||
|
if (_player) {
|
||||||
|
_player->showShadow();
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -2432,11 +2456,16 @@ void MainWidget::showBackFromStack() {
|
||||||
|
|
||||||
void MainWidget::orderWidgets() {
|
void MainWidget::orderWidgets() {
|
||||||
_topBar->raise();
|
_topBar->raise();
|
||||||
_player->raise();
|
|
||||||
_dialogs->raise();
|
_dialogs->raise();
|
||||||
|
if (_player) {
|
||||||
|
_player->raise();
|
||||||
|
}
|
||||||
|
if (_playerVolume) {
|
||||||
|
_playerVolume->raise();
|
||||||
|
}
|
||||||
_mediaType->raise();
|
_mediaType->raise();
|
||||||
_sideShadow.raise();
|
_sideShadow->raise();
|
||||||
if (_mediaPlayer) _mediaPlayer->raise();
|
if (_playerPanel) _playerPanel->raise();
|
||||||
if (_hider) _hider->raise();
|
if (_hider) _hider->raise();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2450,12 +2479,18 @@ QRect MainWidget::historyRect() const {
|
||||||
QPixmap MainWidget::grabForShowAnimation(const Window::SectionSlideParams ¶ms) {
|
QPixmap MainWidget::grabForShowAnimation(const Window::SectionSlideParams ¶ms) {
|
||||||
_topBar->stopAnim();
|
_topBar->stopAnim();
|
||||||
QPixmap result;
|
QPixmap result;
|
||||||
|
if (_player) {
|
||||||
|
_player->hideShadow();
|
||||||
|
}
|
||||||
if (Adaptive::OneColumn()) {
|
if (Adaptive::OneColumn()) {
|
||||||
result = myGrab(this, QRect(0, _playerHeight, _dialogsWidth, height() - _playerHeight));
|
result = myGrab(this, QRect(0, _playerHeight, _dialogsWidth, height() - _playerHeight));
|
||||||
} else {
|
} else {
|
||||||
_sideShadow.hide();
|
_sideShadow->hide();
|
||||||
result = myGrab(this, QRect(_dialogsWidth, _playerHeight, width() - _dialogsWidth, height() - _playerHeight));
|
result = myGrab(this, QRect(_dialogsWidth, _playerHeight, width() - _dialogsWidth, height() - _playerHeight));
|
||||||
_sideShadow.show();
|
_sideShadow->show();
|
||||||
|
}
|
||||||
|
if (_player) {
|
||||||
|
_player->showShadow();
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -2602,11 +2637,11 @@ void MainWidget::hideAll() {
|
||||||
if (_overview) {
|
if (_overview) {
|
||||||
_overview->hide();
|
_overview->hide();
|
||||||
}
|
}
|
||||||
_sideShadow.hide();
|
_sideShadow->hide();
|
||||||
_topBar->hide();
|
_topBar->hide();
|
||||||
_mediaType->hide();
|
_mediaType->hide();
|
||||||
if (_player->isOpened() && !_player->isHidden()) {
|
if (_player) {
|
||||||
_player->hidePlayer();
|
_player->hide();
|
||||||
_playerHeight = 0;
|
_playerHeight = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2617,7 +2652,7 @@ void MainWidget::showAll() {
|
||||||
Ui::showLayer(new InformBox(lang(lng_signin_password_removed)));
|
Ui::showLayer(new InformBox(lang(lng_signin_password_removed)));
|
||||||
}
|
}
|
||||||
if (Adaptive::OneColumn()) {
|
if (Adaptive::OneColumn()) {
|
||||||
_sideShadow.hide();
|
_sideShadow->hide();
|
||||||
if (_hider) {
|
if (_hider) {
|
||||||
_hider->hide();
|
_hider->hide();
|
||||||
if (!_forwardConfirm && _hider->wasOffered()) {
|
if (!_forwardConfirm && _hider->wasOffered()) {
|
||||||
|
@ -2654,7 +2689,7 @@ void MainWidget::showAll() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_sideShadow.show();
|
_sideShadow->show();
|
||||||
if (_hider) {
|
if (_hider) {
|
||||||
_hider->show();
|
_hider->show();
|
||||||
if (_forwardConfirm) {
|
if (_forwardConfirm) {
|
||||||
|
@ -2677,9 +2712,9 @@ void MainWidget::showAll() {
|
||||||
_topBar->show();
|
_topBar->show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_player->isOpened() && _player->isHidden()) {
|
if (_player) {
|
||||||
_player->showPlayer();
|
_player->show();
|
||||||
_playerHeight = _player->height();
|
_playerHeight = _player->contentHeight();
|
||||||
}
|
}
|
||||||
resizeEvent(0);
|
resizeEvent(0);
|
||||||
|
|
||||||
|
@ -2695,30 +2730,35 @@ inline int chatsListWidth(int windowWidth) {
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void MainWidget::resizeEvent(QResizeEvent *e) {
|
void MainWidget::resizeEvent(QResizeEvent *e) {
|
||||||
int32 tbh = _topBar->isHidden() ? 0 : st::topBarHeight;
|
updateControlsGeometry();
|
||||||
updateMediaPlayerPosition();
|
}
|
||||||
|
|
||||||
|
void MainWidget::updateControlsGeometry() {
|
||||||
|
auto tbh = _topBar->isHidden() ? 0 : st::topBarHeight;
|
||||||
if (Adaptive::OneColumn()) {
|
if (Adaptive::OneColumn()) {
|
||||||
_dialogsWidth = width();
|
_dialogsWidth = width();
|
||||||
_player->setGeometry(0, 0, _dialogsWidth, _player->height());
|
if (_player) {
|
||||||
|
_player->resizeToWidth(_dialogsWidth);
|
||||||
|
_player->moveToLeft(0, 0);
|
||||||
|
}
|
||||||
_dialogs->setGeometry(0, _playerHeight, _dialogsWidth, height() - _playerHeight);
|
_dialogs->setGeometry(0, _playerHeight, _dialogsWidth, height() - _playerHeight);
|
||||||
_topBar->setGeometry(0, _playerHeight, _dialogsWidth, st::topBarHeight);
|
_topBar->setGeometry(0, _playerHeight, _dialogsWidth, st::topBarHeight);
|
||||||
_history->setGeometry(0, _playerHeight + tbh, _dialogsWidth, height() - _playerHeight - tbh);
|
_history->setGeometry(0, _playerHeight + tbh, _dialogsWidth, height() - _playerHeight - tbh);
|
||||||
if (_hider) _hider->setGeometry(0, 0, _dialogsWidth, height());
|
if (_hider) _hider->setGeometry(0, 0, _dialogsWidth, height());
|
||||||
} else {
|
} else {
|
||||||
_dialogsWidth = chatsListWidth(width());
|
_dialogsWidth = chatsListWidth(width());
|
||||||
_dialogs->resize(_dialogsWidth, height());
|
auto sectionWidth = width() - _dialogsWidth;
|
||||||
_dialogs->moveToLeft(0, 0);
|
|
||||||
_sideShadow.resize(st::lineWidth, height());
|
_dialogs->setGeometryToLeft(0, 0, _dialogsWidth, height());
|
||||||
_sideShadow.moveToLeft(_dialogsWidth, 0);
|
_sideShadow->setGeometryToLeft(_dialogsWidth, 0, st::lineWidth, height());
|
||||||
_player->resize(width() - _dialogsWidth, _player->height());
|
if (_player) {
|
||||||
_player->moveToLeft(_dialogsWidth, 0);
|
_player->resizeToWidth(sectionWidth);
|
||||||
_topBar->resize(width() - _dialogsWidth, st::topBarHeight);
|
_player->moveToLeft(_dialogsWidth, 0);
|
||||||
_topBar->moveToLeft(_dialogsWidth, _playerHeight);
|
}
|
||||||
_history->resize(width() - _dialogsWidth, height() - _playerHeight - tbh);
|
_topBar->setGeometryToLeft(_dialogsWidth, _playerHeight, sectionWidth, st::topBarHeight);
|
||||||
_history->moveToLeft(_dialogsWidth, _playerHeight + tbh);
|
_history->setGeometryToLeft(_dialogsWidth, _playerHeight + tbh, sectionWidth, height() - _playerHeight - tbh);
|
||||||
if (_hider) {
|
if (_hider) {
|
||||||
_hider->resize(width() - _dialogsWidth, height());
|
_hider->setGeometryToLeft(_dialogsWidth, 0, sectionWidth, height());
|
||||||
_hider->moveToLeft(_dialogsWidth, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_mediaType->moveToLeft(width() - _mediaType->width(), _playerHeight + st::topBarHeight);
|
_mediaType->moveToLeft(width() - _mediaType->width(), _playerHeight + st::topBarHeight);
|
||||||
|
@ -2727,12 +2767,18 @@ void MainWidget::resizeEvent(QResizeEvent *e) {
|
||||||
_wideSection->setGeometryWithTopMoved(wideSectionGeometry, _contentScrollAddToY);
|
_wideSection->setGeometryWithTopMoved(wideSectionGeometry, _contentScrollAddToY);
|
||||||
}
|
}
|
||||||
if (_overview) _overview->setGeometry(_history->geometry());
|
if (_overview) _overview->setGeometry(_history->geometry());
|
||||||
|
updateMediaPlayerPosition();
|
||||||
_contentScrollAddToY = 0;
|
_contentScrollAddToY = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::updateMediaPlayerPosition() {
|
void MainWidget::updateMediaPlayerPosition() {
|
||||||
if (_mediaPlayer) {
|
if (_playerPanel) {
|
||||||
_mediaPlayer->moveToRight(0, 0);
|
_playerPanel->moveToRight(0, 0);
|
||||||
|
}
|
||||||
|
if (_playerVolume && _player) {
|
||||||
|
auto relativePosition = _player->entity()->getPositionForVolumeWidget();
|
||||||
|
auto playerMargins = _playerVolume->getMargin();
|
||||||
|
_playerVolume->moveToLeft(_player->x() + relativePosition.x() - playerMargins.left(), _player->y() + relativePosition.y() - playerMargins.top());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2745,7 +2791,10 @@ void MainWidget::keyPressEvent(QKeyEvent *e) {
|
||||||
|
|
||||||
void MainWidget::updateAdaptiveLayout() {
|
void MainWidget::updateAdaptiveLayout() {
|
||||||
showAll();
|
showAll();
|
||||||
_sideShadow.setVisible(!Adaptive::OneColumn());
|
_sideShadow->setVisible(!Adaptive::OneColumn());
|
||||||
|
if (_player) {
|
||||||
|
_player->updateAdaptiveLayout();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MainWidget::needBackButton() {
|
bool MainWidget::needBackButton() {
|
||||||
|
@ -2807,8 +2856,8 @@ Window::TopBarWidget *MainWidget::topBar() {
|
||||||
return _topBar;
|
return _topBar;
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerWidget *MainWidget::player() {
|
int MainWidget::backgroundFromY() const {
|
||||||
return _player;
|
return (_topBar->isHidden() ? 0 : (-st::topBarHeight)) - _playerHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::onTopBarClick() {
|
void MainWidget::onTopBarClick() {
|
||||||
|
@ -3486,6 +3535,8 @@ void MainWidget::onSelfParticipantUpdated(ChannelData *channel) {
|
||||||
|
|
||||||
bool MainWidget::contentOverlapped(const QRect &globalRect) {
|
bool MainWidget::contentOverlapped(const QRect &globalRect) {
|
||||||
return (_history->contentOverlapped(globalRect) ||
|
return (_history->contentOverlapped(globalRect) ||
|
||||||
|
(_playerPanel && _playerPanel->overlaps(globalRect)) ||
|
||||||
|
(_playerVolume && _playerVolume->overlaps(globalRect)) ||
|
||||||
_mediaType->overlaps(globalRect));
|
_mediaType->overlaps(globalRect));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,14 +31,18 @@ class Row;
|
||||||
namespace Media {
|
namespace Media {
|
||||||
namespace Player {
|
namespace Player {
|
||||||
class Widget;
|
class Widget;
|
||||||
|
class VolumeWidget;
|
||||||
|
class Panel;
|
||||||
} // namespace Player
|
} // namespace Player
|
||||||
} // namespace Media
|
} // namespace Media
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class PeerAvatarButton;
|
class PeerAvatarButton;
|
||||||
|
class PlainShadow;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Window {
|
namespace Window {
|
||||||
|
class PlayerWrapWidget;
|
||||||
class TopBarWidget;
|
class TopBarWidget;
|
||||||
class SectionMemento;
|
class SectionMemento;
|
||||||
class SectionWidget;
|
class SectionWidget;
|
||||||
|
@ -51,7 +55,6 @@ class ConfirmBox;
|
||||||
class DialogsWidget;
|
class DialogsWidget;
|
||||||
class HistoryWidget;
|
class HistoryWidget;
|
||||||
class OverviewWidget;
|
class OverviewWidget;
|
||||||
class PlayerWidget;
|
|
||||||
class HistoryHider;
|
class HistoryHider;
|
||||||
class Dropdown;
|
class Dropdown;
|
||||||
|
|
||||||
|
@ -128,9 +131,7 @@ enum NotifySettingStatus {
|
||||||
|
|
||||||
namespace InlineBots {
|
namespace InlineBots {
|
||||||
namespace Layout {
|
namespace Layout {
|
||||||
|
|
||||||
class ItemBase;
|
class ItemBase;
|
||||||
|
|
||||||
} // namespace Layout
|
} // namespace Layout
|
||||||
} // namespace InlineBots
|
} // namespace InlineBots
|
||||||
|
|
||||||
|
@ -147,8 +148,8 @@ public:
|
||||||
QRect getMembersShowAreaGeometry() const;
|
QRect getMembersShowAreaGeometry() const;
|
||||||
void setMembersShowAreaActive(bool active);
|
void setMembersShowAreaActive(bool active);
|
||||||
Window::TopBarWidget *topBar();
|
Window::TopBarWidget *topBar();
|
||||||
|
int backgroundFromY() const;
|
||||||
|
|
||||||
PlayerWidget *player();
|
|
||||||
int contentScrollAddToY() const;
|
int contentScrollAddToY() const;
|
||||||
|
|
||||||
void animShow(const QPixmap &bgAnimCache, bool back = false);
|
void animShow(const QPixmap &bgAnimCache, bool back = false);
|
||||||
|
@ -379,8 +380,6 @@ public:
|
||||||
|
|
||||||
bool isItemVisible(HistoryItem *item);
|
bool isItemVisible(HistoryItem *item);
|
||||||
|
|
||||||
void closePlayer();
|
|
||||||
|
|
||||||
void documentLoadProgress(DocumentData *document);
|
void documentLoadProgress(DocumentData *document);
|
||||||
|
|
||||||
void app_sendBotCallback(const HistoryMessageReplyMarkup::Button *button, const HistoryItem *msg, int row, int col);
|
void app_sendBotCallback(const HistoryMessageReplyMarkup::Button *button, const HistoryItem *msg, int row, int col);
|
||||||
|
@ -488,6 +487,12 @@ private:
|
||||||
void updateAdaptiveLayout();
|
void updateAdaptiveLayout();
|
||||||
void handleAudioUpdate(const AudioMsgId &audioId);
|
void handleAudioUpdate(const AudioMsgId &audioId);
|
||||||
void updateMediaPlayerPosition();
|
void updateMediaPlayerPosition();
|
||||||
|
void updateControlsGeometry();
|
||||||
|
|
||||||
|
void createPlayer();
|
||||||
|
void switchToPanelPlayer();
|
||||||
|
void switchToFixedPlayer();
|
||||||
|
void playerHeightUpdated();
|
||||||
|
|
||||||
void sendReadRequest(PeerData *peer, MsgId upTo);
|
void sendReadRequest(PeerData *peer, MsgId upTo);
|
||||||
void channelReadDone(PeerData *peer, const MTPBool &result);
|
void channelReadDone(PeerData *peer, const MTPBool &result);
|
||||||
|
@ -581,15 +586,15 @@ private:
|
||||||
|
|
||||||
int _dialogsWidth;
|
int _dialogsWidth;
|
||||||
|
|
||||||
PlainShadow _sideShadow;
|
ChildWidget<Ui::PlainShadow> _sideShadow;
|
||||||
|
|
||||||
ChildWidget<DialogsWidget> _dialogs;
|
ChildWidget<DialogsWidget> _dialogs;
|
||||||
ChildWidget<HistoryWidget> _history;
|
ChildWidget<HistoryWidget> _history;
|
||||||
ChildWidget<Window::SectionWidget> _wideSection = { nullptr };
|
ChildWidget<Window::SectionWidget> _wideSection = { nullptr };
|
||||||
ChildWidget<OverviewWidget> _overview = { nullptr };
|
ChildWidget<OverviewWidget> _overview = { nullptr };
|
||||||
ChildWidget<PlayerWidget> _player;
|
|
||||||
ChildWidget<Window::TopBarWidget> _topBar;
|
ChildWidget<Window::TopBarWidget> _topBar;
|
||||||
ChildWidget<Media::Player::Widget> _mediaPlayer = { nullptr };
|
ChildWidget<Window::PlayerWrapWidget> _player = { nullptr };
|
||||||
|
ChildWidget<Media::Player::VolumeWidget> _playerVolume = { nullptr };
|
||||||
|
ChildWidget<Media::Player::Panel> _playerPanel = { nullptr };
|
||||||
ConfirmBox *_forwardConfirm = nullptr; // for single column layout
|
ConfirmBox *_forwardConfirm = nullptr; // for single column layout
|
||||||
ChildWidget<HistoryHider> _hider = { nullptr };
|
ChildWidget<HistoryHider> _hider = { nullptr };
|
||||||
std_::vector_of_moveable<std_::unique_ptr<StackItem>> _stack;
|
std_::vector_of_moveable<std_::unique_ptr<StackItem>> _stack;
|
||||||
|
|
|
@ -286,21 +286,21 @@ void AudioPlayer::AudioMsg::clear() {
|
||||||
videoPlayId = 0;
|
videoPlayId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioPlayer::AudioPlayer() : _audioCurrent(0), _songCurrent(0),
|
AudioPlayer::AudioPlayer()
|
||||||
_fader(new AudioPlayerFader(&_faderThread)),
|
: _fader(new AudioPlayerFader(&_faderThread))
|
||||||
_loader(new AudioPlayerLoaders(&_loaderThread)) {
|
, _loader(new AudioPlayerLoaders(&_loaderThread)) {
|
||||||
connect(this, SIGNAL(faderOnTimer()), _fader, SLOT(onTimer()));
|
connect(this, SIGNAL(faderOnTimer()), _fader, SLOT(onTimer()));
|
||||||
connect(this, SIGNAL(suppressSong()), _fader, SLOT(onSuppressSong()));
|
connect(this, SIGNAL(suppressSong()), _fader, SLOT(onSuppressSong()));
|
||||||
connect(this, SIGNAL(unsuppressSong()), _fader, SLOT(onUnsuppressSong()));
|
connect(this, SIGNAL(unsuppressSong()), _fader, SLOT(onUnsuppressSong()));
|
||||||
connect(this, SIGNAL(suppressAll()), _fader, SLOT(onSuppressAll()));
|
connect(this, SIGNAL(suppressAll()), _fader, SLOT(onSuppressAll()));
|
||||||
connect(this, SIGNAL(songVolumeChanged()), _fader, SLOT(onSongVolumeChanged()));
|
subscribe(Global::RefSongVolumeChanged(), [this] {
|
||||||
connect(this, SIGNAL(videoVolumeChanged()), _fader, SLOT(onVideoVolumeChanged()));
|
QMetaObject::invokeMethod(_fader, "onSongVolumeChanged");
|
||||||
|
});
|
||||||
|
subscribe(Global::RefVideoVolumeChanged(), [this] {
|
||||||
|
QMetaObject::invokeMethod(_fader, "onVideoVolumeChanged");
|
||||||
|
});
|
||||||
connect(this, SIGNAL(loaderOnStart(const AudioMsgId&,qint64)), _loader, SLOT(onStart(const AudioMsgId&,qint64)));
|
connect(this, SIGNAL(loaderOnStart(const AudioMsgId&,qint64)), _loader, SLOT(onStart(const AudioMsgId&,qint64)));
|
||||||
connect(this, SIGNAL(loaderOnCancel(const AudioMsgId&)), _loader, SLOT(onCancel(const AudioMsgId&)));
|
connect(this, SIGNAL(loaderOnCancel(const AudioMsgId&)), _loader, SLOT(onCancel(const AudioMsgId&)));
|
||||||
connect(&_faderThread, SIGNAL(started()), _fader, SLOT(onInit()));
|
|
||||||
connect(&_loaderThread, SIGNAL(started()), _loader, SLOT(onInit()));
|
|
||||||
connect(&_faderThread, SIGNAL(finished()), _fader, SLOT(deleteLater()));
|
|
||||||
connect(&_loaderThread, SIGNAL(finished()), _loader, SLOT(deleteLater()));
|
|
||||||
connect(_loader, SIGNAL(needToCheck()), _fader, SLOT(onTimer()));
|
connect(_loader, SIGNAL(needToCheck()), _fader, SLOT(onTimer()));
|
||||||
connect(_loader, SIGNAL(error(const AudioMsgId&)), this, SLOT(onError(const AudioMsgId&)));
|
connect(_loader, SIGNAL(error(const AudioMsgId&)), this, SLOT(onError(const AudioMsgId&)));
|
||||||
connect(_fader, SIGNAL(needToPreload(const AudioMsgId&)), _loader, SLOT(onLoad(const AudioMsgId&)));
|
connect(_fader, SIGNAL(needToPreload(const AudioMsgId&)), _loader, SLOT(onLoad(const AudioMsgId&)));
|
||||||
|
@ -309,6 +309,7 @@ _loader(new AudioPlayerLoaders(&_loaderThread)) {
|
||||||
connect(_fader, SIGNAL(error(const AudioMsgId&)), this, SLOT(onError(const AudioMsgId&)));
|
connect(_fader, SIGNAL(error(const AudioMsgId&)), this, SLOT(onError(const AudioMsgId&)));
|
||||||
connect(this, SIGNAL(stoppedOnError(const AudioMsgId&)), this, SIGNAL(updated(const AudioMsgId&)), Qt::QueuedConnection);
|
connect(this, SIGNAL(stoppedOnError(const AudioMsgId&)), this, SIGNAL(updated(const AudioMsgId&)), Qt::QueuedConnection);
|
||||||
connect(this, SIGNAL(updated(const AudioMsgId&)), this, SLOT(onUpdated(const AudioMsgId&)));
|
connect(this, SIGNAL(updated(const AudioMsgId&)), this, SLOT(onUpdated(const AudioMsgId&)));
|
||||||
|
|
||||||
_loaderThread.start();
|
_loaderThread.start();
|
||||||
_faderThread.start();
|
_faderThread.start();
|
||||||
}
|
}
|
||||||
|
@ -446,6 +447,7 @@ bool AudioPlayer::fadedStop(AudioMsgId::Type type, bool *fadedStart) {
|
||||||
void AudioPlayer::play(const AudioMsgId &audio, int64 position) {
|
void AudioPlayer::play(const AudioMsgId &audio, int64 position) {
|
||||||
auto type = audio.type();
|
auto type = audio.type();
|
||||||
AudioMsgId stopped;
|
AudioMsgId stopped;
|
||||||
|
auto notLoadedYet = false;
|
||||||
{
|
{
|
||||||
QMutexLocker lock(&playerMutex);
|
QMutexLocker lock(&playerMutex);
|
||||||
|
|
||||||
|
@ -479,14 +481,11 @@ void AudioPlayer::play(const AudioMsgId &audio, int64 position) {
|
||||||
current->file = audio.audio()->location(true);
|
current->file = audio.audio()->location(true);
|
||||||
current->data = audio.audio()->data();
|
current->data = audio.audio()->data();
|
||||||
if (current->file.isEmpty() && current->data.isEmpty()) {
|
if (current->file.isEmpty() && current->data.isEmpty()) {
|
||||||
|
notLoadedYet = true;
|
||||||
if (audio.type() == AudioMsgId::Type::Song) {
|
if (audio.type() == AudioMsgId::Type::Song) {
|
||||||
setStoppedState(current);
|
setStoppedState(current);
|
||||||
if (!audio.audio()->loading()) {
|
|
||||||
DocumentOpenClickHandler::doOpen(audio.audio());
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
setStoppedState(current, AudioPlayerStoppedAtError);
|
setStoppedState(current, AudioPlayerStoppedAtError);
|
||||||
onError(audio);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
current->playbackState.position = position;
|
current->playbackState.position = position;
|
||||||
|
@ -498,7 +497,16 @@ void AudioPlayer::play(const AudioMsgId &audio, int64 position) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (stopped) emit updated(stopped);
|
if (notLoadedYet) {
|
||||||
|
if (audio.type() == AudioMsgId::Type::Song) {
|
||||||
|
DocumentOpenClickHandler::doOpen(audio.audio(), App::histItemById(audio.contextId()));
|
||||||
|
} else {
|
||||||
|
onError(audio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (stopped) {
|
||||||
|
emit updated(stopped);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioPlayer::initFromVideo(uint64 videoPlayId, std_::unique_ptr<VideoSoundData> &&data, int64 position) {
|
void AudioPlayer::initFromVideo(uint64 videoPlayId, std_::unique_ptr<VideoSoundData> &&data, int64 position) {
|
||||||
|
@ -949,13 +957,15 @@ AudioCapture *audioCapture() {
|
||||||
return capture;
|
return capture;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioPlayerFader::AudioPlayerFader(QThread *thread) : _timer(this), _pauseFlag(false), _paused(true),
|
AudioPlayerFader::AudioPlayerFader(QThread *thread) : QObject()
|
||||||
_suppressAll(false), _suppressAllAnim(false), _suppressSong(false), _suppressSongAnim(false),
|
, _timer(this)
|
||||||
_suppressAllGain(1., 1.), _suppressSongGain(1., 1.),
|
, _suppressAllGain(1., 1.)
|
||||||
_suppressAllStart(0), _suppressSongStart(0) {
|
, _suppressSongGain(1., 1.) {
|
||||||
moveToThread(thread);
|
moveToThread(thread);
|
||||||
_timer.moveToThread(thread);
|
_timer.moveToThread(thread);
|
||||||
_pauseTimer.moveToThread(thread);
|
_pauseTimer.moveToThread(thread);
|
||||||
|
connect(thread, SIGNAL(started()), this, SLOT(onInit()));
|
||||||
|
connect(thread, SIGNAL(finished()), this, SLOT(deleteLater()));
|
||||||
|
|
||||||
_timer.setSingleShot(true);
|
_timer.setSingleShot(true);
|
||||||
connect(&_timer, SIGNAL(timeout()), this, SLOT(onTimer()));
|
connect(&_timer, SIGNAL(timeout()), this, SLOT(onTimer()));
|
||||||
|
|
|
@ -55,7 +55,7 @@ struct AudioPlaybackState {
|
||||||
int32 frequency = 0;
|
int32 frequency = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AudioPlayer : public QObject, public base::Observable<AudioMsgId> {
|
class AudioPlayer : public QObject, public base::Observable<AudioMsgId>, private base::Subscriber {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -103,9 +103,6 @@ signals:
|
||||||
void unsuppressSong();
|
void unsuppressSong();
|
||||||
void suppressAll();
|
void suppressAll();
|
||||||
|
|
||||||
void songVolumeChanged();
|
|
||||||
void videoVolumeChanged();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool fadedStop(AudioMsgId::Type type, bool *fadedStart = 0);
|
bool fadedStop(AudioMsgId::Type type, bool *fadedStart = 0);
|
||||||
bool updateCurrentStarted(AudioMsgId::Type type, int32 pos = -1);
|
bool updateCurrentStarted(AudioMsgId::Type type, int32 pos = -1);
|
||||||
|
@ -150,10 +147,10 @@ private:
|
||||||
int *currentIndex(AudioMsgId::Type type);
|
int *currentIndex(AudioMsgId::Type type);
|
||||||
const int *currentIndex(AudioMsgId::Type type) const;
|
const int *currentIndex(AudioMsgId::Type type) const;
|
||||||
|
|
||||||
int _audioCurrent;
|
int _audioCurrent = 0;
|
||||||
AudioMsg _audioData[AudioSimultaneousLimit];
|
AudioMsg _audioData[AudioSimultaneousLimit];
|
||||||
|
|
||||||
int _songCurrent;
|
int _songCurrent = 0;
|
||||||
AudioMsg _songData[AudioSimultaneousLimit];
|
AudioMsg _songData[AudioSimultaneousLimit];
|
||||||
|
|
||||||
AudioMsg _videoData;
|
AudioMsg _videoData;
|
||||||
|
@ -252,11 +249,17 @@ private:
|
||||||
|
|
||||||
QTimer _timer, _pauseTimer;
|
QTimer _timer, _pauseTimer;
|
||||||
QMutex _pauseMutex;
|
QMutex _pauseMutex;
|
||||||
bool _pauseFlag, _paused;
|
bool _pauseFlag = false;
|
||||||
|
bool _paused = true;
|
||||||
|
|
||||||
bool _suppressAll, _suppressAllAnim, _suppressSong, _suppressSongAnim, _songVolumeChanged, _videoVolumeChanged;
|
bool _suppressAll = false;
|
||||||
|
bool _suppressAllAnim = false;
|
||||||
|
bool _suppressSong = false;
|
||||||
|
bool _suppressSongAnim = false;
|
||||||
|
bool _songVolumeChanged, _videoVolumeChanged;
|
||||||
anim::fvalue _suppressAllGain, _suppressSongGain;
|
anim::fvalue _suppressAllGain, _suppressSongGain;
|
||||||
uint64 _suppressAllStart, _suppressSongStart;
|
uint64 _suppressAllStart = 0;
|
||||||
|
uint64 _suppressSongStart = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
AudioPlayerLoaders::AudioPlayerLoaders(QThread *thread) : _fromVideoNotify(this, "onVideoSoundAdded") {
|
AudioPlayerLoaders::AudioPlayerLoaders(QThread *thread) : _fromVideoNotify(this, "onVideoSoundAdded") {
|
||||||
moveToThread(thread);
|
moveToThread(thread);
|
||||||
|
connect(thread, SIGNAL(started()), this, SLOT(onInit()));
|
||||||
|
connect(thread, SIGNAL(finished()), this, SLOT(deleteLater()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioPlayerLoaders::feedFromVideo(VideoSoundPart &&part) {
|
void AudioPlayerLoaders::feedFromVideo(VideoSoundPart &&part) {
|
||||||
|
|
|
@ -33,6 +33,127 @@ MediaPlayerButton {
|
||||||
cancelStroke: pixels;
|
cancelStroke: pixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mediaPlayerActiveFg: #54b5ed;
|
||||||
|
mediaPlayerInactiveFg: #dfebf2;
|
||||||
|
|
||||||
|
mediaPlayerButton: MediaPlayerButton {
|
||||||
|
playPosition: point(2px, 0px);
|
||||||
|
playOuter: size(17px, 15px);
|
||||||
|
pausePosition: point(1px, 1px);
|
||||||
|
pauseOuter: size(15px, 15px);
|
||||||
|
pauseStroke: 5px;
|
||||||
|
cancelPosition: point(1px, 1px);
|
||||||
|
cancelOuter: size(15px, 15px);
|
||||||
|
cancelStroke: 3px;
|
||||||
|
}
|
||||||
|
mediaPlayerButtonSize: size(25px, 30px);
|
||||||
|
|
||||||
|
mediaPlayerButtonPosition: point(5px, 10px);
|
||||||
|
mediaPlayerSkipIconPosition: point(5px, 12px);
|
||||||
|
|
||||||
|
mediaPlayerHeight: 35px;
|
||||||
|
mediaPlayerPadding: 8px;
|
||||||
|
mediaPlayerNameTop: 22px;
|
||||||
|
mediaPlayerPlayLeft: 7px;
|
||||||
|
mediaPlayerPlaySkip: 1px;
|
||||||
|
mediaPlayerPlayTop: 0px;
|
||||||
|
mediaPlayerCloseRight: 0px;
|
||||||
|
|
||||||
|
mediaPlayerName: flatLabel(labelDefFlat) {
|
||||||
|
maxHeight: 20px;
|
||||||
|
textFg: windowTextFg;
|
||||||
|
}
|
||||||
|
mediaPlayerTime: LabelSimple(defaultLabelSimple) {
|
||||||
|
textFg: windowSubTextFg;
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaPlayerRepeatButton: IconButton {
|
||||||
|
width: 31px;
|
||||||
|
height: 30px;
|
||||||
|
|
||||||
|
opacity: 1.;
|
||||||
|
overOpacity: 1.;
|
||||||
|
|
||||||
|
icon: icon {
|
||||||
|
{ "player_repeat", mediaPlayerActiveFg, point(9px, 11px) }
|
||||||
|
};
|
||||||
|
iconPosition: point(0px, 0px);
|
||||||
|
downIconPosition: point(0px, 0px);
|
||||||
|
|
||||||
|
duration: 0;
|
||||||
|
}
|
||||||
|
mediaPlayerRepeatDisabledIcon: icon {
|
||||||
|
{ "player_repeat", #c8c8c8, point(9px, 11px)}
|
||||||
|
};
|
||||||
|
mediaPlayerRepeatInactiveIcon: icon {
|
||||||
|
{ "player_repeat", mediaPlayerInactiveFg, point(9px, 11px)}
|
||||||
|
};
|
||||||
|
|
||||||
|
mediaPlayerVolumeIcon0: icon {
|
||||||
|
{ "player_volume0", mediaPlayerActiveFg },
|
||||||
|
};
|
||||||
|
mediaPlayerVolumeIcon1: icon {
|
||||||
|
{ "player_volume1", mediaPlayerActiveFg },
|
||||||
|
};
|
||||||
|
mediaPlayerVolumeIcon2: icon {
|
||||||
|
{ "player_volume2", mediaPlayerActiveFg },
|
||||||
|
};
|
||||||
|
mediaPlayerVolumeIcon3: icon {
|
||||||
|
{ "player_volume3", mediaPlayerActiveFg },
|
||||||
|
};
|
||||||
|
mediaPlayerVolumeToggle: IconButton {
|
||||||
|
width: 31px;
|
||||||
|
height: 30px;
|
||||||
|
|
||||||
|
opacity: 1.;
|
||||||
|
overOpacity: 1.;
|
||||||
|
|
||||||
|
icon: mediaPlayerVolumeIcon0;
|
||||||
|
iconPosition: point(8px, 11px);
|
||||||
|
downIconPosition: point(8px, 11px);
|
||||||
|
|
||||||
|
duration: 0;
|
||||||
|
}
|
||||||
|
mediaPlayerVolumeMargin: 10px;
|
||||||
|
mediaPlayerVolumeSize: size(27px, 100px);
|
||||||
|
|
||||||
|
mediaPlayerPanelPinButton: IconButton(mediaPlayerRepeatButton) {
|
||||||
|
icon: icon {
|
||||||
|
{ "player_panel_pin", mediaPlayerActiveFg, point(9px, 11px) }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaPlayerNextButton: IconButton(mediaPlayerRepeatButton) {
|
||||||
|
width: 25px;
|
||||||
|
icon: icon {
|
||||||
|
{ "player_next", mediaPlayerActiveFg, mediaPlayerSkipIconPosition },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
mediaPlayerNextDisabledIcon: icon {
|
||||||
|
{ "player_next", mediaPlayerInactiveFg, mediaPlayerSkipIconPosition },
|
||||||
|
};
|
||||||
|
mediaPlayerPreviousButton: IconButton(mediaPlayerNextButton) {
|
||||||
|
icon: icon {
|
||||||
|
{ "player_previous", mediaPlayerActiveFg, mediaPlayerSkipIconPosition },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
mediaPlayerPreviousDisabledIcon: icon {
|
||||||
|
{ "player_previous", mediaPlayerInactiveFg, mediaPlayerSkipIconPosition },
|
||||||
|
};
|
||||||
|
mediaPlayerClose: IconButton(mediaPlayerRepeatButton) {
|
||||||
|
width: 37px;
|
||||||
|
icon: icon {
|
||||||
|
{ "player_close", #c8c8c8, point(10px, 12px) },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
mediaPlayerPlayback: FilledSlider {
|
||||||
|
fullWidth: 6px;
|
||||||
|
lineWidth: 2px;
|
||||||
|
activeFg: mediaPlayerActiveFg;
|
||||||
|
inactiveFg: mediaPlayerInactiveFg;
|
||||||
|
duration: 150;
|
||||||
|
}
|
||||||
|
|
||||||
mediaPlayerTitleButtonSize: size(titleHeight, titleHeight);
|
mediaPlayerTitleButtonSize: size(titleHeight, titleHeight);
|
||||||
mediaPlayerTitleButtonInner: size(25px, 25px);
|
mediaPlayerTitleButtonInner: size(25px, 25px);
|
||||||
mediaPlayerTitleButtonInnerBg: #49708f;
|
mediaPlayerTitleButtonInnerBg: #49708f;
|
||||||
|
@ -48,7 +169,8 @@ mediaPlayerTitleButton: MediaPlayerButton {
|
||||||
cancelOuter: size(25px, 25px);
|
cancelOuter: size(25px, 25px);
|
||||||
cancelStroke: 2px;
|
cancelStroke: 2px;
|
||||||
}
|
}
|
||||||
mediaPlayerButton: MediaPlayerButton {
|
|
||||||
|
mediaPlayerPanelButton: MediaPlayerButton {
|
||||||
playPosition: point(3px, 0px);
|
playPosition: point(3px, 0px);
|
||||||
playOuter: size(22px, 18px);
|
playOuter: size(22px, 18px);
|
||||||
pausePosition: point(1px, 1px);
|
pausePosition: point(1px, 1px);
|
||||||
|
@ -58,62 +180,40 @@ mediaPlayerButton: MediaPlayerButton {
|
||||||
cancelOuter: size(16px, 18px);
|
cancelOuter: size(16px, 18px);
|
||||||
cancelStroke: 3px;
|
cancelStroke: 3px;
|
||||||
}
|
}
|
||||||
|
mediaPlayerPanelButtonSize: size(32px, 32px);
|
||||||
|
mediaPlayerPanelButtonPosition: point(8px, 7px);
|
||||||
|
|
||||||
mediaPlayerMarginLeft: 10px;
|
mediaPlayerPanelMarginLeft: 10px;
|
||||||
mediaPlayerMarginBottom: 10px;
|
mediaPlayerPanelMarginBottom: 10px;
|
||||||
mediaPlayerWidth: 344px;
|
mediaPlayerPanelWidth: 344px;
|
||||||
mediaPlayerCoverHeight: 102px;
|
mediaPlayerCoverHeight: 102px;
|
||||||
|
|
||||||
mediaPlayerActiveFg: #54b5ed;
|
mediaPlayerPanelNextButton: IconButton(mediaPlayerRepeatButton) {
|
||||||
mediaPlayerInactiveFg: #dfebf2;
|
|
||||||
|
|
||||||
mediaPlayerButtonSize: size(32px, 32px);
|
|
||||||
mediaPlayerButtonPosition: point(8px, 7px);
|
|
||||||
|
|
||||||
mediaPlayerRepeatButton: IconButton {
|
|
||||||
width: 31px;
|
|
||||||
height: 32px;
|
|
||||||
|
|
||||||
opacity: 1.;
|
|
||||||
overOpacity: 1.;
|
|
||||||
|
|
||||||
icon: icon {
|
|
||||||
{ "player_repeat", mediaPlayerActiveFg, point(9px, 9px)}
|
|
||||||
};
|
|
||||||
iconPosition: point(0px, 0px);
|
|
||||||
downIconPosition: point(0px, 0px);
|
|
||||||
|
|
||||||
duration: 0;
|
|
||||||
}
|
|
||||||
mediaPlayerRepeatDisabledIcon: icon {
|
|
||||||
{ "player_repeat", mediaPlayerInactiveFg, point(9px, 9px)}
|
|
||||||
};
|
|
||||||
mediaPlayerPreviousButton: IconButton(mediaPlayerRepeatButton) {
|
|
||||||
width: 37px;
|
width: 37px;
|
||||||
icon: icon {
|
icon: icon {
|
||||||
{ "player_previous", mediaPlayerActiveFg, point(10px, 10px) },
|
{ "player_panel_next", mediaPlayerActiveFg, point(10px, 10px) },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
mediaPlayerPreviousDisabledIcon: icon {
|
mediaPlayerPanelNextDisabledIcon: icon {
|
||||||
{ "player_previous", mediaPlayerInactiveFg, point(10px, 10px) },
|
{ "player_panel_next", mediaPlayerInactiveFg, point(10px, 10px) },
|
||||||
};
|
};
|
||||||
mediaPlayerNextButton: IconButton(mediaPlayerPreviousButton) {
|
mediaPlayerPanelPreviousButton: IconButton(mediaPlayerPanelNextButton) {
|
||||||
icon: icon {
|
icon: icon {
|
||||||
{ "player_next", mediaPlayerActiveFg, point(10px, 10px) },
|
{ "player_panel_previous", mediaPlayerActiveFg, point(10px, 10px) },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
mediaPlayerNextDisabledIcon: icon {
|
mediaPlayerPanelPreviousDisabledIcon: icon {
|
||||||
{ "player_next", mediaPlayerInactiveFg, point(10px, 10px) },
|
{ "player_panel_previous", mediaPlayerInactiveFg, point(10px, 10px) },
|
||||||
};
|
};
|
||||||
|
|
||||||
mediaPlayerPadding: 18px;
|
mediaPlayerPanelPadding: 18px;
|
||||||
mediaPlayerNameTop: 24px;
|
mediaPlayerPanelNameTop: 24px;
|
||||||
mediaPlayerPlayLeft: 9px;
|
mediaPlayerPanelPlayLeft: 9px;
|
||||||
mediaPlayerPlaySkip: 7px;
|
mediaPlayerPanelPlaySkip: 7px;
|
||||||
mediaPlayerPlayTop: 58px;
|
mediaPlayerPanelPlayTop: 58px;
|
||||||
mediaPlayerPlaybackTop: 32px;
|
mediaPlayerPanelPlaybackTop: 32px;
|
||||||
mediaPlayerPlaybackPadding: 8px;
|
mediaPlayerPanelPlaybackPadding: 8px;
|
||||||
mediaPlayerPlayback: MediaSlider {
|
mediaPlayerPanelPlayback: MediaSlider {
|
||||||
width: 3px;
|
width: 3px;
|
||||||
activeFg: mediaPlayerActiveFg;
|
activeFg: mediaPlayerActiveFg;
|
||||||
inactiveFg: mediaPlayerInactiveFg;
|
inactiveFg: mediaPlayerInactiveFg;
|
||||||
|
@ -123,41 +223,8 @@ mediaPlayerPlayback: MediaSlider {
|
||||||
duration: 150;
|
duration: 150;
|
||||||
}
|
}
|
||||||
|
|
||||||
mediaPlayerName: flatLabel(labelDefFlat) {
|
mediaPlayerPanelVolumeTop: 65px;
|
||||||
maxHeight: 20px;
|
mediaPlayerPanelVolumeSkip: 3px;
|
||||||
textFg: windowTextFg;
|
mediaPlayerPanelVolumeWidth: 64px;
|
||||||
}
|
mediaPlayerPanelVolumeToggleSkip: 0px;
|
||||||
mediaPlayerTime: LabelSimple(defaultLabelSimple) {
|
mediaPlayerPanelVolumeToggleTop: 57px;
|
||||||
textFg: windowSubTextFg;
|
|
||||||
}
|
|
||||||
|
|
||||||
mediaPlayerVolumeTop: 65px;
|
|
||||||
mediaPlayerVolumeRight: 51px;
|
|
||||||
mediaPlayerVolumeWidth: 86px;
|
|
||||||
mediaPlayerVolumeLength: 64px;
|
|
||||||
|
|
||||||
mediaPlayerVolumeIcon0: icon {
|
|
||||||
{ "player_volume0", mediaPlayerActiveFg },
|
|
||||||
};
|
|
||||||
mediaPlayerVolumeIcon1: icon {
|
|
||||||
{ "player_volume1", mediaPlayerActiveFg },
|
|
||||||
};
|
|
||||||
mediaPlayerVolumeIcon2: icon {
|
|
||||||
{ "player_volume2", mediaPlayerActiveFg },
|
|
||||||
};
|
|
||||||
mediaPlayerVolumeIcon3: icon {
|
|
||||||
{ "player_volume3", mediaPlayerActiveFg },
|
|
||||||
};
|
|
||||||
mediaPlayerVolumeToggle: IconButton {
|
|
||||||
width: 18px;
|
|
||||||
height: 17px;
|
|
||||||
|
|
||||||
opacity: 1.;
|
|
||||||
overOpacity: 1.;
|
|
||||||
|
|
||||||
icon: mediaPlayerVolumeIcon0;
|
|
||||||
iconPosition: point(0px, 2px);
|
|
||||||
downIconPosition: point(0px, 2px);
|
|
||||||
|
|
||||||
duration: 0;
|
|
||||||
}
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "ui/flatlabel.h"
|
#include "ui/flatlabel.h"
|
||||||
#include "ui/widgets/label_simple.h"
|
#include "ui/widgets/label_simple.h"
|
||||||
|
#include "ui/widgets/media_slider.h"
|
||||||
#include "ui/buttons/icon_button.h"
|
#include "ui/buttons/icon_button.h"
|
||||||
#include "media/media_audio.h"
|
#include "media/media_audio.h"
|
||||||
#include "media/view/media_clip_playback.h"
|
#include "media/view/media_clip_playback.h"
|
||||||
|
@ -31,7 +32,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "media/player/media_player_volume_controller.h"
|
#include "media/player/media_player_volume_controller.h"
|
||||||
#include "styles/style_media_player.h"
|
#include "styles/style_media_player.h"
|
||||||
#include "styles/style_mediaview.h"
|
#include "styles/style_mediaview.h"
|
||||||
#include "shortcuts.h"
|
|
||||||
|
|
||||||
namespace Media {
|
namespace Media {
|
||||||
namespace Player {
|
namespace Player {
|
||||||
|
@ -42,7 +42,7 @@ class CoverWidget::PlayButton : public Button {
|
||||||
public:
|
public:
|
||||||
PlayButton(QWidget *parent);
|
PlayButton(QWidget *parent);
|
||||||
|
|
||||||
void setState(State state) {
|
void setState(PlayButtonLayout::State state) {
|
||||||
_layout.setState(state);
|
_layout.setState(state);
|
||||||
}
|
}
|
||||||
void finishTransform() {
|
void finishTransform() {
|
||||||
|
@ -58,24 +58,26 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
CoverWidget::PlayButton::PlayButton(QWidget *parent) : Button(parent)
|
CoverWidget::PlayButton::PlayButton(QWidget *parent) : Button(parent)
|
||||||
, _layout(st::mediaPlayerButton, [this] { update(); }) {
|
, _layout(st::mediaPlayerPanelButton, [this] { update(); }) {
|
||||||
resize(st::mediaPlayerButtonSize);
|
resize(st::mediaPlayerPanelButtonSize);
|
||||||
setCursor(style::cur_pointer);
|
setCursor(style::cur_pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoverWidget::PlayButton::paintEvent(QPaintEvent *e) {
|
void CoverWidget::PlayButton::paintEvent(QPaintEvent *e) {
|
||||||
Painter p(this);
|
Painter p(this);
|
||||||
|
|
||||||
p.translate(st::mediaPlayerButtonPosition.x(), st::mediaPlayerButtonPosition.y());
|
p.translate(st::mediaPlayerPanelButtonPosition.x(), st::mediaPlayerPanelButtonPosition.y());
|
||||||
_layout.paint(p, st::mediaPlayerActiveFg);
|
_layout.paint(p, st::mediaPlayerActiveFg);
|
||||||
}
|
}
|
||||||
|
|
||||||
CoverWidget::CoverWidget(QWidget *parent) : TWidget(parent)
|
CoverWidget::CoverWidget(QWidget *parent) : TWidget(parent)
|
||||||
, _nameLabel(this, st::mediaPlayerName)
|
, _nameLabel(this, st::mediaPlayerName)
|
||||||
, _timeLabel(this, st::mediaPlayerTime)
|
, _timeLabel(this, st::mediaPlayerTime)
|
||||||
, _playback(this, st::mediaPlayerPlayback)
|
, _playback(new Ui::MediaSlider(this, st::mediaPlayerPanelPlayback))
|
||||||
, _playPause(this)
|
, _playPause(this)
|
||||||
|
, _volumeToggle(this, st::mediaPlayerVolumeToggle)
|
||||||
, _volumeController(this)
|
, _volumeController(this)
|
||||||
|
, _pinPlayer(this, st::mediaPlayerPanelPinButton)
|
||||||
, _repeatTrack(this, st::mediaPlayerRepeatButton) {
|
, _repeatTrack(this, st::mediaPlayerRepeatButton) {
|
||||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||||
|
|
||||||
|
@ -85,26 +87,34 @@ CoverWidget::CoverWidget(QWidget *parent) : TWidget(parent)
|
||||||
_playback->setChangeFinishedCallback([this](float64 value) {
|
_playback->setChangeFinishedCallback([this](float64 value) {
|
||||||
handleSeekFinished(value);
|
handleSeekFinished(value);
|
||||||
});
|
});
|
||||||
_playPause->setClickedCallback([this]() {
|
_playPause->setClickedCallback([this] {
|
||||||
if (exists()) {
|
if (exists()) {
|
||||||
instance()->playPauseCancelClicked();
|
instance()->playPauseCancelClicked();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
updateRepeatTrackIcon();
|
updateRepeatTrackIcon();
|
||||||
_repeatTrack->setClickedCallback([this]() {
|
_repeatTrack->setClickedCallback([this] {
|
||||||
instance()->toggleRepeat();
|
instance()->toggleRepeat();
|
||||||
updateRepeatTrackIcon();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
updateVolumeToggleIcon();
|
||||||
|
_volumeToggle->setClickedCallback([this]() {
|
||||||
|
Global::SetSongVolume((Global::SongVolume() > 0) ? 0. : Global::RememberedSongVolume());
|
||||||
|
Global::RefSongVolumeChanged().notify();
|
||||||
|
});
|
||||||
|
subscribe(Global::RefSongVolumeChanged(), [this] { updateVolumeToggleIcon(); });
|
||||||
if (exists()) {
|
if (exists()) {
|
||||||
subscribe(instance()->playlistChangedNotifier(), [this]() {
|
subscribe(instance()->repeatChangedNotifier(), [this] {
|
||||||
|
updateRepeatTrackIcon();
|
||||||
|
});
|
||||||
|
subscribe(instance()->playlistChangedNotifier(), [this] {
|
||||||
handlePlaylistUpdate();
|
handlePlaylistUpdate();
|
||||||
});
|
});
|
||||||
subscribe(instance()->updatedNotifier(), [this](const UpdatedEvent &e) {
|
subscribe(instance()->updatedNotifier(), [this](const UpdatedEvent &e) {
|
||||||
handleSongUpdate(e);
|
handleSongUpdate(e);
|
||||||
});
|
});
|
||||||
subscribe(instance()->songChangedNotifier(), [this]() {
|
subscribe(instance()->songChangedNotifier(), [this] {
|
||||||
handleSongChange();
|
handleSongChange();
|
||||||
});
|
});
|
||||||
handleSongChange();
|
handleSongChange();
|
||||||
|
@ -117,6 +127,10 @@ CoverWidget::CoverWidget(QWidget *parent) : TWidget(parent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CoverWidget::setPinCallback(PinCallback &&callback) {
|
||||||
|
_pinPlayer->setClickedCallback(std_::move(callback));
|
||||||
|
}
|
||||||
|
|
||||||
void CoverWidget::handleSeekProgress(float64 progress) {
|
void CoverWidget::handleSeekProgress(float64 progress) {
|
||||||
if (!_lastDurationMs) return;
|
if (!_lastDurationMs) return;
|
||||||
|
|
||||||
|
@ -148,15 +162,22 @@ void CoverWidget::handleSeekFinished(float64 progress) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoverWidget::resizeEvent(QResizeEvent *e) {
|
void CoverWidget::resizeEvent(QResizeEvent *e) {
|
||||||
_nameLabel->resizeToWidth(width() - 2 * (st::mediaPlayerPadding) - _timeLabel->width() - st::normalFont->spacew);
|
auto widthForName = width() - 2 * (st::mediaPlayerPanelPadding);
|
||||||
|
widthForName -= _timeLabel->width() + 2 * st::normalFont->spacew;
|
||||||
|
_nameLabel->resizeToWidth(widthForName);
|
||||||
updateLabelPositions();
|
updateLabelPositions();
|
||||||
|
|
||||||
int skip = (st::mediaPlayerPlayback.seekSize.width() / 2);
|
int skip = (st::mediaPlayerPanelPlayback.seekSize.width() / 2);
|
||||||
int length = (width() - 2 * st::mediaPlayerPadding + st::mediaPlayerPlayback.seekSize.width());
|
int length = (width() - 2 * st::mediaPlayerPanelPadding + st::mediaPlayerPanelPlayback.seekSize.width());
|
||||||
_playback->setGeometry(st::mediaPlayerPadding - skip, st::mediaPlayerPlaybackTop, length, 2 * st::mediaPlayerPlaybackPadding + st::mediaPlayerPlayback.width);
|
_playback->setGeometry(st::mediaPlayerPanelPadding - skip, st::mediaPlayerPanelPlaybackTop, length, 2 * st::mediaPlayerPanelPlaybackPadding + st::mediaPlayerPanelPlayback.width);
|
||||||
|
|
||||||
|
auto top = st::mediaPlayerPanelVolumeToggleTop;
|
||||||
|
auto right = st::mediaPlayerPanelPlayLeft;
|
||||||
|
_repeatTrack->moveToRight(right, top); right += _repeatTrack->width();
|
||||||
|
_pinPlayer->moveToRight(right, top); right += _pinPlayer->width() + st::mediaPlayerPanelVolumeSkip;
|
||||||
|
_volumeController->moveToRight(right, st::mediaPlayerPanelVolumeTop); right += _volumeController->width() + st::mediaPlayerPanelVolumeToggleSkip;
|
||||||
|
_volumeToggle->moveToRight(right, top);
|
||||||
|
|
||||||
_repeatTrack->moveToRight(st::mediaPlayerPlayLeft, st::mediaPlayerPlayTop);
|
|
||||||
_volumeController->moveToRight(st::mediaPlayerVolumeRight, st::mediaPlayerVolumeTop);
|
|
||||||
updatePlayPrevNextPositions();
|
updatePlayPrevNextPositions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,23 +187,24 @@ void CoverWidget::paintEvent(QPaintEvent *e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoverWidget::updatePlayPrevNextPositions() {
|
void CoverWidget::updatePlayPrevNextPositions() {
|
||||||
|
auto left = st::mediaPlayerPanelPlayLeft;
|
||||||
|
auto top = st::mediaPlayerPanelPlayTop;
|
||||||
if (_previousTrack) {
|
if (_previousTrack) {
|
||||||
auto left = st::mediaPlayerPlayLeft;
|
_previousTrack->moveToLeft(left, top); left += _previousTrack->width() + st::mediaPlayerPanelPlaySkip;
|
||||||
_previousTrack->moveToLeft(left, st::mediaPlayerPlayTop); left += _previousTrack->width() + st::mediaPlayerPlaySkip;
|
_playPause->moveToLeft(left, top); left += _playPause->width() + st::mediaPlayerPanelPlaySkip;
|
||||||
_playPause->moveToLeft(left, st::mediaPlayerPlayTop); left += _playPause->width() + st::mediaPlayerPlaySkip;
|
_nextTrack->moveToLeft(left, top);
|
||||||
_nextTrack->moveToLeft(left, st::mediaPlayerPlayTop);
|
|
||||||
} else {
|
} else {
|
||||||
_playPause->moveToLeft(st::mediaPlayerPlayLeft, st::mediaPlayerPlayTop);
|
_playPause->moveToLeft(left, top);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoverWidget::updateLabelPositions() {
|
void CoverWidget::updateLabelPositions() {
|
||||||
_nameLabel->moveToLeft(st::mediaPlayerPadding, st::mediaPlayerNameTop - st::mediaPlayerName.font->ascent);
|
_nameLabel->moveToLeft(st::mediaPlayerPanelPadding, st::mediaPlayerPanelNameTop - st::mediaPlayerName.font->ascent);
|
||||||
_timeLabel->moveToRight(st::mediaPlayerPadding, st::mediaPlayerNameTop - st::mediaPlayerTime.font->ascent);
|
_timeLabel->moveToRight(st::mediaPlayerPanelPadding, st::mediaPlayerPanelNameTop - st::mediaPlayerTime.font->ascent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoverWidget::updateRepeatTrackIcon() {
|
void CoverWidget::updateRepeatTrackIcon() {
|
||||||
_repeatTrack->setIcon(instance()->repeatEnabled() ? nullptr : &st::mediaPlayerRepeatDisabledIcon);
|
_repeatTrack->setIcon(instance()->repeatEnabled() ? nullptr : &st::mediaPlayerRepeatInactiveIcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoverWidget::handleSongUpdate(const UpdatedEvent &e) {
|
void CoverWidget::handleSongUpdate(const UpdatedEvent &e) {
|
||||||
|
@ -249,7 +271,7 @@ void CoverWidget::updateTimeLabel() {
|
||||||
_timeLabel->setText(_time);
|
_timeLabel->setText(_time);
|
||||||
}
|
}
|
||||||
if (timeLabelWidth != _timeLabel->width()) {
|
if (timeLabelWidth != _timeLabel->width()) {
|
||||||
_nameLabel->resizeToWidth(width() - 2 * (st::mediaPlayerPadding) - _timeLabel->width() - st::normalFont->spacew);
|
_nameLabel->resizeToWidth(width() - 2 * (st::mediaPlayerPanelPadding) - _timeLabel->width() - st::normalFont->spacew);
|
||||||
updateLabelPositions();
|
updateLabelPositions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -281,17 +303,17 @@ void CoverWidget::handlePlaylistUpdate() {
|
||||||
createPrevNextButtons();
|
createPrevNextButtons();
|
||||||
auto previousEnabled = (index > 0);
|
auto previousEnabled = (index > 0);
|
||||||
auto nextEnabled = (index + 1 < playlist.size());
|
auto nextEnabled = (index + 1 < playlist.size());
|
||||||
_previousTrack->setIcon(previousEnabled ? nullptr : &st::mediaPlayerPreviousDisabledIcon);
|
_previousTrack->setIcon(previousEnabled ? nullptr : &st::mediaPlayerPanelPreviousDisabledIcon);
|
||||||
_previousTrack->setCursor(previousEnabled ? style::cur_pointer : style::cur_default);
|
_previousTrack->setCursor(previousEnabled ? style::cur_pointer : style::cur_default);
|
||||||
_nextTrack->setIcon(nextEnabled ? nullptr : &st::mediaPlayerNextDisabledIcon);
|
_nextTrack->setIcon(nextEnabled ? nullptr : &st::mediaPlayerPanelNextDisabledIcon);
|
||||||
_nextTrack->setCursor(nextEnabled ? style::cur_pointer : style::cur_default);
|
_nextTrack->setCursor(nextEnabled ? style::cur_pointer : style::cur_default);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoverWidget::createPrevNextButtons() {
|
void CoverWidget::createPrevNextButtons() {
|
||||||
if (!_previousTrack) {
|
if (!_previousTrack) {
|
||||||
_previousTrack.create(this, st::mediaPlayerPreviousButton);
|
_previousTrack.create(this, st::mediaPlayerPanelPreviousButton);
|
||||||
_nextTrack.create(this, st::mediaPlayerNextButton);
|
_nextTrack.create(this, st::mediaPlayerPanelNextButton);
|
||||||
_previousTrack->setClickedCallback([this]() {
|
_previousTrack->setClickedCallback([this]() {
|
||||||
if (exists()) {
|
if (exists()) {
|
||||||
instance()->previous();
|
instance()->previous();
|
||||||
|
@ -314,5 +336,21 @@ void CoverWidget::destroyPrevNextButtons() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CoverWidget::updateVolumeToggleIcon() {
|
||||||
|
auto icon = []() -> const style::icon * {
|
||||||
|
auto volume = Global::SongVolume();
|
||||||
|
if (volume > 0) {
|
||||||
|
if (volume < 1 / 3.) {
|
||||||
|
return &st::mediaPlayerVolumeIcon1;
|
||||||
|
} else if (volume < 2 / 3.) {
|
||||||
|
return &st::mediaPlayerVolumeIcon2;
|
||||||
|
}
|
||||||
|
return &st::mediaPlayerVolumeIcon3;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
};
|
||||||
|
_volumeToggle->setIcon(icon());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Player
|
} // namespace Player
|
||||||
} // namespace Media
|
} // namespace Media
|
||||||
|
|
|
@ -35,7 +35,6 @@ class Playback;
|
||||||
|
|
||||||
namespace Player {
|
namespace Player {
|
||||||
|
|
||||||
class PlaybackWidget;
|
|
||||||
class VolumeController;
|
class VolumeController;
|
||||||
struct UpdatedEvent;
|
struct UpdatedEvent;
|
||||||
|
|
||||||
|
@ -43,6 +42,9 @@ class CoverWidget : public TWidget, private base::Subscriber {
|
||||||
public:
|
public:
|
||||||
CoverWidget(QWidget *parent);
|
CoverWidget(QWidget *parent);
|
||||||
|
|
||||||
|
using PinCallback = base::lambda_unique<void()>;
|
||||||
|
void setPinCallback(PinCallback &&callback);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
void paintEvent(QPaintEvent *e) override;
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
@ -57,6 +59,8 @@ private:
|
||||||
void createPrevNextButtons();
|
void createPrevNextButtons();
|
||||||
void destroyPrevNextButtons();
|
void destroyPrevNextButtons();
|
||||||
|
|
||||||
|
void updateVolumeToggleIcon();
|
||||||
|
|
||||||
void handleSongUpdate(const UpdatedEvent &e);
|
void handleSongUpdate(const UpdatedEvent &e);
|
||||||
void handleSongChange();
|
void handleSongChange();
|
||||||
void handlePlaylistUpdate();
|
void handlePlaylistUpdate();
|
||||||
|
@ -75,7 +79,9 @@ private:
|
||||||
ChildWidget<Ui::IconButton> _previousTrack = { nullptr };
|
ChildWidget<Ui::IconButton> _previousTrack = { nullptr };
|
||||||
ChildWidget<PlayButton> _playPause;
|
ChildWidget<PlayButton> _playPause;
|
||||||
ChildWidget<Ui::IconButton> _nextTrack = { nullptr };
|
ChildWidget<Ui::IconButton> _nextTrack = { nullptr };
|
||||||
|
ChildWidget<Ui::IconButton> _volumeToggle;
|
||||||
ChildWidget<VolumeController> _volumeController;
|
ChildWidget<VolumeController> _volumeController;
|
||||||
|
ChildWidget<Ui::IconButton> _pinPlayer;
|
||||||
ChildWidget<Ui::IconButton> _repeatTrack;
|
ChildWidget<Ui::IconButton> _repeatTrack;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -84,6 +84,8 @@ void Instance::handleSongUpdate(const AudioMsgId &audioId) {
|
||||||
void Instance::setCurrent(const AudioMsgId &audioId) {
|
void Instance::setCurrent(const AudioMsgId &audioId) {
|
||||||
if (_current != audioId) {
|
if (_current != audioId) {
|
||||||
_current = audioId;
|
_current = audioId;
|
||||||
|
_isPlaying = false;
|
||||||
|
|
||||||
auto history = _history, migrated = _migrated;
|
auto history = _history, migrated = _migrated;
|
||||||
auto item = _current ? App::histItemById(_current.contextId()) : nullptr;
|
auto item = _current ? App::histItemById(_current.contextId()) : nullptr;
|
||||||
if (item) {
|
if (item) {
|
||||||
|
@ -263,7 +265,36 @@ void Instance::emitUpdate(CheckCallback check) {
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_isPlaying = !(playbackState.state & AudioPlayerStoppedMask);
|
auto isPlaying = !(playbackState.state & AudioPlayerStoppedMask);
|
||||||
|
if (_isPlaying != isPlaying) {
|
||||||
|
_isPlaying = isPlaying;
|
||||||
|
if (_isPlaying) {
|
||||||
|
preloadNext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Instance::preloadNext() {
|
||||||
|
if (!_current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto index = _playlist.indexOf(_current.contextId());
|
||||||
|
if (index < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto nextIndex = index + 1;
|
||||||
|
if (nextIndex >= _playlist.size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (auto item = App::histItemById(_playlist[nextIndex])) {
|
||||||
|
if (auto media = item->getMedia()) {
|
||||||
|
if (auto document = media->getDocument()) {
|
||||||
|
if (!document->loaded(DocumentData::FilePathResolveSaveFromDataSilent)) {
|
||||||
|
DocumentOpenClickHandler::doOpen(document, nullptr, ActionOnLoadNone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Player
|
} // namespace Player
|
||||||
|
|
|
@ -40,11 +40,11 @@ bool exists();
|
||||||
class Instance;
|
class Instance;
|
||||||
Instance *instance();
|
Instance *instance();
|
||||||
|
|
||||||
class Widget;
|
class Panel;
|
||||||
struct CreatedEvent {
|
struct PanelEvent {
|
||||||
explicit CreatedEvent(Widget *widget) : widget(widget) {
|
explicit PanelEvent(Panel *panel) : panel(panel) {
|
||||||
}
|
}
|
||||||
Widget *widget;
|
Panel *panel;
|
||||||
};
|
};
|
||||||
struct UpdatedEvent {
|
struct UpdatedEvent {
|
||||||
UpdatedEvent(const AudioMsgId *audioId, const AudioPlaybackState *playbackState) : audioId(audioId), playbackState(playbackState) {
|
UpdatedEvent(const AudioMsgId *audioId, const AudioPlaybackState *playbackState) : audioId(audioId), playbackState(playbackState) {
|
||||||
|
@ -74,6 +74,7 @@ public:
|
||||||
}
|
}
|
||||||
void toggleRepeat() {
|
void toggleRepeat() {
|
||||||
_repeatEnabled = !_repeatEnabled;
|
_repeatEnabled = !_repeatEnabled;
|
||||||
|
_repeatChangedNotifier.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSeeking() const {
|
bool isSeeking() const {
|
||||||
|
@ -86,9 +87,12 @@ public:
|
||||||
return _playlist;
|
return _playlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
base::Observable<CreatedEvent> &createdNotifier() {
|
base::Observable<PanelEvent> &createdNotifier() {
|
||||||
return _createdNotifier;
|
return _createdNotifier;
|
||||||
}
|
}
|
||||||
|
base::Observable<PanelEvent> &destroyedNotifier() {
|
||||||
|
return _destroyedNotifier;
|
||||||
|
}
|
||||||
base::Observable<UpdatedEvent> &updatedNotifier() {
|
base::Observable<UpdatedEvent> &updatedNotifier() {
|
||||||
return _updatedNotifier;
|
return _updatedNotifier;
|
||||||
}
|
}
|
||||||
|
@ -98,6 +102,9 @@ public:
|
||||||
base::Observable<void> &songChangedNotifier() {
|
base::Observable<void> &songChangedNotifier() {
|
||||||
return _songChangedNotifier;
|
return _songChangedNotifier;
|
||||||
}
|
}
|
||||||
|
base::Observable<void> &repeatChangedNotifier() {
|
||||||
|
return _repeatChangedNotifier;
|
||||||
|
}
|
||||||
|
|
||||||
void documentLoadProgress(DocumentData *document);
|
void documentLoadProgress(DocumentData *document);
|
||||||
|
|
||||||
|
@ -112,6 +119,7 @@ private:
|
||||||
void setCurrent(const AudioMsgId &audioId);
|
void setCurrent(const AudioMsgId &audioId);
|
||||||
void rebuildPlaylist();
|
void rebuildPlaylist();
|
||||||
void moveInPlaylist(int delta);
|
void moveInPlaylist(int delta);
|
||||||
|
void preloadNext();
|
||||||
|
|
||||||
template <typename CheckCallback>
|
template <typename CheckCallback>
|
||||||
void emitUpdate(CheckCallback check);
|
void emitUpdate(CheckCallback check);
|
||||||
|
@ -125,10 +133,12 @@ private:
|
||||||
QList<FullMsgId> _playlist;
|
QList<FullMsgId> _playlist;
|
||||||
bool _isPlaying = false;
|
bool _isPlaying = false;
|
||||||
|
|
||||||
base::Observable<CreatedEvent> _createdNotifier;
|
base::Observable<PanelEvent> _createdNotifier;
|
||||||
|
base::Observable<PanelEvent> _destroyedNotifier;
|
||||||
base::Observable<UpdatedEvent> _updatedNotifier;
|
base::Observable<UpdatedEvent> _updatedNotifier;
|
||||||
base::Observable<void> _playlistChangedNotifier;
|
base::Observable<void> _playlistChangedNotifier;
|
||||||
base::Observable<void> _songChangedNotifier;
|
base::Observable<void> _songChangedNotifier;
|
||||||
|
base::Observable<void> _repeatChangedNotifier;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,225 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop 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 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It 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.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "media/player/media_player_panel.h"
|
||||||
|
|
||||||
|
#include "media/player/media_player_cover.h"
|
||||||
|
#include "media/player/media_player_list.h"
|
||||||
|
#include "media/player/media_player_instance.h"
|
||||||
|
#include "styles/style_media_player.h"
|
||||||
|
#include "mainwindow.h"
|
||||||
|
|
||||||
|
namespace Media {
|
||||||
|
namespace Player {
|
||||||
|
|
||||||
|
Panel::Panel(QWidget *parent, Layout layout) : TWidget(parent)
|
||||||
|
, _shadow(st::defaultInnerDropdown.shadow) {
|
||||||
|
if (layout == Layout::Full) {
|
||||||
|
_cover.create(this);
|
||||||
|
}
|
||||||
|
_hideTimer.setSingleShot(true);
|
||||||
|
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(onHideStart()));
|
||||||
|
|
||||||
|
_showTimer.setSingleShot(true);
|
||||||
|
connect(&_showTimer, SIGNAL(timeout()), this, SLOT(onShowStart()));
|
||||||
|
|
||||||
|
if (_scroll) {
|
||||||
|
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::mediaPlayerPanelWidth, st::mediaPlayerCoverHeight + st::mediaPlayerPanelMarginBottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Panel::overlaps(const QRect &globalRect) {
|
||||||
|
if (isHidden() || _a_appearance.animating()) return false;
|
||||||
|
|
||||||
|
auto marginLeft = rtl() ? 0 : contentLeft();
|
||||||
|
auto marginRight = rtl() ? contentLeft() : 0;
|
||||||
|
return rect().marginsRemoved(QMargins(marginLeft, 0, marginRight, st::mediaPlayerPanelMarginBottom)).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panel::onWindowActiveChanged() {
|
||||||
|
if (!App::wnd()->windowHandle()->isActive() && !isHidden()) {
|
||||||
|
leaveEvent(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panel::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<ScrolledWidget*>(_scroll->widget())) {
|
||||||
|
// widget->resizeToWidth(_scroll->width());
|
||||||
|
// onScroll();
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panel::onScroll() {
|
||||||
|
//if (auto widget = static_cast<ScrolledWidget*>(_scroll->widget())) {
|
||||||
|
// int visibleTop = _scroll->scrollTop();
|
||||||
|
// int visibleBottom = visibleTop + _scroll->height();
|
||||||
|
// widget->setVisibleTopBottom(visibleTop, visibleBottom);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panel::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::mediaPlayerPanelMarginBottom);
|
||||||
|
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 Panel::enterEvent(QEvent *e) {
|
||||||
|
_hideTimer.stop();
|
||||||
|
if (_a_appearance.animating(getms())) {
|
||||||
|
onShowStart();
|
||||||
|
} else {
|
||||||
|
_showTimer.start(0);
|
||||||
|
}
|
||||||
|
return TWidget::enterEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panel::leaveEvent(QEvent *e) {
|
||||||
|
_showTimer.stop();
|
||||||
|
if (_a_appearance.animating(getms())) {
|
||||||
|
onHideStart();
|
||||||
|
} else {
|
||||||
|
_hideTimer.start(300);
|
||||||
|
}
|
||||||
|
return TWidget::leaveEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panel::otherEnter() {
|
||||||
|
_hideTimer.stop();
|
||||||
|
if (_a_appearance.animating(getms())) {
|
||||||
|
onShowStart();
|
||||||
|
} else {
|
||||||
|
_showTimer.start(300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panel::otherLeave() {
|
||||||
|
_showTimer.stop();
|
||||||
|
if (_a_appearance.animating(getms())) {
|
||||||
|
onHideStart();
|
||||||
|
} else {
|
||||||
|
_hideTimer.start(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panel::setPinCallback(PinCallback &&callback) {
|
||||||
|
if (_cover) {
|
||||||
|
_cover->setPinCallback(std_::move(callback));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Panel::~Panel() {
|
||||||
|
if (exists()) {
|
||||||
|
instance()->destroyedNotifier().notify(Media::Player::PanelEvent(this), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panel::onShowStart() {
|
||||||
|
if (isHidden()) {
|
||||||
|
show();
|
||||||
|
} else if (!_hiding) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_hiding = false;
|
||||||
|
startAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panel::onHideStart() {
|
||||||
|
if (_hiding) return;
|
||||||
|
|
||||||
|
_hiding = true;
|
||||||
|
startAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panel::startAnimation() {
|
||||||
|
auto from = _hiding ? 1. : 0.;
|
||||||
|
auto to = _hiding ? 0. : 1.;
|
||||||
|
if (!_a_appearance.animating()) {
|
||||||
|
showChildren();
|
||||||
|
_cache = myGrab(this);
|
||||||
|
}
|
||||||
|
hideChildren();
|
||||||
|
_a_appearance.start([this] { appearanceCallback(); }, from, to, st::defaultInnerDropdown.duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panel::appearanceCallback() {
|
||||||
|
if (!_a_appearance.animating() && _hiding) {
|
||||||
|
_hiding = false;
|
||||||
|
hidingFinished();
|
||||||
|
} else {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panel::hidingFinished() {
|
||||||
|
hide();
|
||||||
|
showChildren();
|
||||||
|
}
|
||||||
|
|
||||||
|
int Panel::contentLeft() const {
|
||||||
|
return st::mediaPlayerPanelMarginLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Panel::eventFilter(QObject *obj, QEvent *e) {
|
||||||
|
if (e->type() == QEvent::Enter) {
|
||||||
|
otherEnter();
|
||||||
|
} else if (e->type() == QEvent::Leave) {
|
||||||
|
otherLeave();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Player
|
||||||
|
} // namespace Media
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop 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 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It 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.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ui/effects/rect_shadow.h"
|
||||||
|
|
||||||
|
class ScrollArea;
|
||||||
|
|
||||||
|
namespace Media {
|
||||||
|
namespace Player {
|
||||||
|
|
||||||
|
class CoverWidget;
|
||||||
|
class ListWidget;
|
||||||
|
|
||||||
|
class Panel : public TWidget, private base::Subscriber {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum class Layout {
|
||||||
|
Full,
|
||||||
|
OnlyPlaylist,
|
||||||
|
};
|
||||||
|
Panel(QWidget *parent, Layout layout);
|
||||||
|
|
||||||
|
void setLayout(Layout layout);
|
||||||
|
bool overlaps(const QRect &globalRect);
|
||||||
|
|
||||||
|
void otherEnter();
|
||||||
|
void otherLeave();
|
||||||
|
|
||||||
|
using PinCallback = base::lambda_unique<void()>;
|
||||||
|
void setPinCallback(PinCallback &&callback);
|
||||||
|
|
||||||
|
~Panel();
|
||||||
|
|
||||||
|
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 appearanceCallback();
|
||||||
|
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<CoverWidget> _cover = { nullptr };
|
||||||
|
ChildWidget<ListWidget> _list = { nullptr };
|
||||||
|
ChildWidget<ScrollArea> _scroll = { nullptr };
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Clip
|
||||||
|
} // namespace Media
|
|
@ -26,65 +26,217 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "ui/widgets/media_slider.h"
|
#include "ui/widgets/media_slider.h"
|
||||||
#include "styles/style_media_player.h"
|
#include "styles/style_media_player.h"
|
||||||
#include "styles/style_widgets.h"
|
#include "styles/style_widgets.h"
|
||||||
|
#include "mainwindow.h"
|
||||||
|
|
||||||
namespace Media {
|
namespace Media {
|
||||||
namespace Player {
|
namespace Player {
|
||||||
|
|
||||||
VolumeController::VolumeController(QWidget *parent) : TWidget(parent)
|
VolumeController::VolumeController(QWidget *parent) : TWidget(parent)
|
||||||
, _toggle(this, st::mediaPlayerVolumeToggle)
|
, _slider(this, st::mediaPlayerPanelPlayback) {
|
||||||
, _slider(this, st::mediaPlayerPlayback) {
|
|
||||||
_toggle->setClickedCallback([this]() {
|
|
||||||
setVolume(_slider->value() ? 0. : _rememberedVolume);
|
|
||||||
});
|
|
||||||
_slider->setChangeProgressCallback([this](float64 volume) {
|
_slider->setChangeProgressCallback([this](float64 volume) {
|
||||||
applyVolumeChange(volume);
|
applyVolumeChange(volume);
|
||||||
});
|
});
|
||||||
_slider->setChangeFinishedCallback([this](float64 volume) {
|
_slider->setChangeFinishedCallback([this](float64 volume) {
|
||||||
if (volume > 0) {
|
if (volume > 0) {
|
||||||
_rememberedVolume = volume;
|
Global::SetRememberedSongVolume(volume);
|
||||||
}
|
}
|
||||||
applyVolumeChange(volume);
|
applyVolumeChange(volume);
|
||||||
});
|
});
|
||||||
|
subscribe(Global::RefSongVolumeChanged(), [this] {
|
||||||
|
if (!_slider->isChanging()) {
|
||||||
|
_slider->setValue(Global::SongVolume(), true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
auto animated = false;
|
auto animated = false;
|
||||||
setVolume(Global::SongVolume(), animated);
|
setVolume(Global::SongVolume(), animated);
|
||||||
|
|
||||||
resize(st::mediaPlayerVolumeWidth, 2 * st::mediaPlayerPlaybackPadding + st::mediaPlayerPlayback.width);
|
resize(st::mediaPlayerPanelVolumeWidth, 2 * st::mediaPlayerPanelPlaybackPadding + st::mediaPlayerPanelPlayback.width);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VolumeController::setIsVertical(bool vertical) {
|
||||||
|
using Direction = Ui::MediaSlider::Direction;
|
||||||
|
_slider->setDirection(vertical ? Direction::Vertical : Direction::Horizontal);
|
||||||
|
_slider->setAlwaysDisplayMarker(vertical);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VolumeController::resizeEvent(QResizeEvent *e) {
|
void VolumeController::resizeEvent(QResizeEvent *e) {
|
||||||
_slider->resize(st::mediaPlayerVolumeLength, height());
|
_slider->setGeometry(rect());
|
||||||
_slider->moveToRight(0, 0);
|
|
||||||
_toggle->moveToLeft(0, (height() - _toggle->height()) / 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VolumeController::setVolume(float64 volume, bool animated) {
|
void VolumeController::setVolume(float64 volume, bool animated) {
|
||||||
_slider->setValue(volume, animated);
|
_slider->setValue(volume, animated);
|
||||||
if (volume > 0) {
|
if (volume > 0) {
|
||||||
_rememberedVolume = volume;
|
Global::SetRememberedSongVolume(volume);
|
||||||
}
|
}
|
||||||
applyVolumeChange(volume);
|
applyVolumeChange(volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VolumeController::applyVolumeChange(float64 volume) {
|
void VolumeController::applyVolumeChange(float64 volume) {
|
||||||
if (volume > 0) {
|
|
||||||
if (volume < 1 / 3.) {
|
|
||||||
_toggle->setIcon(&st::mediaPlayerVolumeIcon1);
|
|
||||||
} else if (volume < 2 / 3.) {
|
|
||||||
_toggle->setIcon(&st::mediaPlayerVolumeIcon2);
|
|
||||||
} else {
|
|
||||||
_toggle->setIcon(&st::mediaPlayerVolumeIcon3);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_toggle->setIcon(nullptr);
|
|
||||||
}
|
|
||||||
if (volume != Global::SongVolume()) {
|
if (volume != Global::SongVolume()) {
|
||||||
Global::SetSongVolume(volume);
|
Global::SetSongVolume(volume);
|
||||||
if (auto player = audioPlayer()) {
|
Global::RefSongVolumeChanged().notify();
|
||||||
emit player->songVolumeChanged();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VolumeWidget::VolumeWidget(QWidget *parent) : TWidget(parent)
|
||||||
|
, _shadow(st::defaultInnerDropdown.shadow)
|
||||||
|
, _controller(this) {
|
||||||
|
hide();
|
||||||
|
_controller->setIsVertical(true);
|
||||||
|
|
||||||
|
_hideTimer.setSingleShot(true);
|
||||||
|
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(onHideStart()));
|
||||||
|
|
||||||
|
_showTimer.setSingleShot(true);
|
||||||
|
connect(&_showTimer, SIGNAL(timeout()), this, SLOT(onShowStart()));
|
||||||
|
|
||||||
|
if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) {
|
||||||
|
connect(App::wnd()->windowHandle(), SIGNAL(activeChanged()), this, SLOT(onWindowActiveChanged()));
|
||||||
|
}
|
||||||
|
|
||||||
|
hide();
|
||||||
|
auto margin = getMargin();
|
||||||
|
resize(margin.left() + st::mediaPlayerVolumeSize.width() + margin.right(), margin.top() + st::mediaPlayerVolumeSize.height() + margin.bottom());
|
||||||
|
}
|
||||||
|
|
||||||
|
QMargins VolumeWidget::getMargin() const {
|
||||||
|
return QMargins(st::mediaPlayerVolumeMargin, st::mediaPlayerPlayback.fullWidth, st::mediaPlayerVolumeMargin, st::mediaPlayerVolumeMargin);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VolumeWidget::overlaps(const QRect &globalRect) {
|
||||||
|
if (isHidden() || _a_appearance.animating()) return false;
|
||||||
|
|
||||||
|
return rect().marginsRemoved(getMargin()).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void VolumeWidget::onWindowActiveChanged() {
|
||||||
|
if (!App::wnd()->windowHandle()->isActive() && !isHidden()) {
|
||||||
|
leaveEvent(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VolumeWidget::resizeEvent(QResizeEvent *e) {
|
||||||
|
auto inner = rect().marginsRemoved(getMargin());
|
||||||
|
_controller->setGeometry(inner.x(), inner.y() - st::lineWidth, inner.width(), inner.height() + st::lineWidth - ((st::mediaPlayerVolumeSize.width() - st::mediaPlayerPanelPlayback.width) / 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void VolumeWidget::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 = rect().marginsRemoved(getMargin());
|
||||||
|
using ShadowSide = Ui::RectShadow::Side;
|
||||||
|
auto shadowedSides = ShadowSide::Left | ShadowSide::Right | ShadowSide::Bottom;
|
||||||
|
_shadow.paint(p, shadowedRect, st::defaultInnerDropdown.shadowShift, shadowedSides);
|
||||||
|
p.fillRect(shadowedRect.x(), 0, shadowedRect.width(), shadowedRect.y() + shadowedRect.height(), st::windowBg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VolumeWidget::enterEvent(QEvent *e) {
|
||||||
|
_hideTimer.stop();
|
||||||
|
if (_a_appearance.animating(getms())) {
|
||||||
|
onShowStart();
|
||||||
|
} else {
|
||||||
|
_showTimer.start(0);
|
||||||
|
}
|
||||||
|
return TWidget::enterEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VolumeWidget::leaveEvent(QEvent *e) {
|
||||||
|
_showTimer.stop();
|
||||||
|
if (_a_appearance.animating(getms())) {
|
||||||
|
onHideStart();
|
||||||
|
} else {
|
||||||
|
_hideTimer.start(300);
|
||||||
|
}
|
||||||
|
return TWidget::leaveEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VolumeWidget::otherEnter() {
|
||||||
|
_hideTimer.stop();
|
||||||
|
if (_a_appearance.animating(getms())) {
|
||||||
|
onShowStart();
|
||||||
|
} else {
|
||||||
|
_showTimer.start(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VolumeWidget::otherLeave() {
|
||||||
|
_showTimer.stop();
|
||||||
|
if (_a_appearance.animating(getms())) {
|
||||||
|
onHideStart();
|
||||||
|
} else {
|
||||||
|
_hideTimer.start(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VolumeWidget::onShowStart() {
|
||||||
|
if (isHidden()) {
|
||||||
|
show();
|
||||||
|
} else if (!_hiding) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_hiding = false;
|
||||||
|
startAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VolumeWidget::onHideStart() {
|
||||||
|
if (_hiding) return;
|
||||||
|
|
||||||
|
_hiding = true;
|
||||||
|
startAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VolumeWidget::startAnimation() {
|
||||||
|
auto from = _hiding ? 1. : 0.;
|
||||||
|
auto to = _hiding ? 0. : 1.;
|
||||||
|
if (_cache.isNull()) {
|
||||||
|
showChildren();
|
||||||
|
_cache = myGrab(this);
|
||||||
|
}
|
||||||
|
hideChildren();
|
||||||
|
_a_appearance.start([this] { appearanceCallback(); }, from, to, st::defaultInnerDropdown.duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VolumeWidget::appearanceCallback() {
|
||||||
|
if (!_a_appearance.animating() && _hiding) {
|
||||||
|
_hiding = false;
|
||||||
|
hidingFinished();
|
||||||
|
} else {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VolumeWidget::hidingFinished() {
|
||||||
|
hide();
|
||||||
|
showChildren();
|
||||||
|
_cache = QPixmap();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VolumeWidget::eventFilter(QObject *obj, QEvent *e) {
|
||||||
|
if (e->type() == QEvent::Enter) {
|
||||||
|
otherEnter();
|
||||||
|
} else if (e->type() == QEvent::Leave) {
|
||||||
|
otherLeave();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Player
|
} // namespace Player
|
||||||
} // namespace Media
|
} // namespace Media
|
||||||
|
|
|
@ -20,18 +20,23 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "ui/effects/rect_shadow.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class IconButton;
|
class IconButton;
|
||||||
class MediaSlider;
|
class MediaSlider;
|
||||||
|
class RectShadow;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Media {
|
namespace Media {
|
||||||
namespace Player {
|
namespace Player {
|
||||||
|
|
||||||
class VolumeController : public TWidget {
|
class VolumeController : public TWidget, private base::Subscriber {
|
||||||
public:
|
public:
|
||||||
VolumeController(QWidget *parent);
|
VolumeController(QWidget *parent);
|
||||||
|
|
||||||
|
void setIsVertical(bool vertical);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
|
|
||||||
|
@ -39,9 +44,50 @@ private:
|
||||||
void setVolume(float64 volume, bool animated = true);
|
void setVolume(float64 volume, bool animated = true);
|
||||||
void applyVolumeChange(float64 volume);
|
void applyVolumeChange(float64 volume);
|
||||||
|
|
||||||
ChildWidget<Ui::IconButton> _toggle;
|
|
||||||
ChildWidget<Ui::MediaSlider> _slider;
|
ChildWidget<Ui::MediaSlider> _slider;
|
||||||
float64 _rememberedVolume = Global::kDefaultVolume;
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class VolumeWidget : public TWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
VolumeWidget(QWidget *parent);
|
||||||
|
|
||||||
|
bool overlaps(const QRect &globalRect);
|
||||||
|
|
||||||
|
void otherEnter();
|
||||||
|
void otherLeave();
|
||||||
|
|
||||||
|
QMargins getMargin() const;
|
||||||
|
|
||||||
|
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 onWindowActiveChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void appearanceCallback();
|
||||||
|
void hidingFinished();
|
||||||
|
void startAnimation();
|
||||||
|
|
||||||
|
bool _hiding = false;
|
||||||
|
|
||||||
|
QPixmap _cache;
|
||||||
|
FloatAnimation _a_appearance;
|
||||||
|
|
||||||
|
QTimer _hideTimer, _showTimer;
|
||||||
|
|
||||||
|
Ui::RectShadow _shadow;
|
||||||
|
ChildWidget<VolumeController> _controller;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -21,189 +21,371 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "media/player/media_player_widget.h"
|
#include "media/player/media_player_widget.h"
|
||||||
|
|
||||||
#include "media/player/media_player_cover.h"
|
#include "ui/flatlabel.h"
|
||||||
#include "media/player/media_player_list.h"
|
#include "ui/widgets/label_simple.h"
|
||||||
|
#include "ui/widgets/filled_slider.h"
|
||||||
|
#include "ui/widgets/shadow.h"
|
||||||
|
#include "ui/buttons/icon_button.h"
|
||||||
|
#include "media/media_audio.h"
|
||||||
|
#include "media/view/media_clip_playback.h"
|
||||||
|
#include "media/player/media_player_button.h"
|
||||||
|
#include "media/player/media_player_instance.h"
|
||||||
|
#include "media/player/media_player_volume_controller.h"
|
||||||
#include "styles/style_media_player.h"
|
#include "styles/style_media_player.h"
|
||||||
#include "mainwindow.h"
|
#include "styles/style_mediaview.h"
|
||||||
|
|
||||||
namespace Media {
|
namespace Media {
|
||||||
namespace Player {
|
namespace Player {
|
||||||
|
|
||||||
|
using State = PlayButtonLayout::State;
|
||||||
|
|
||||||
|
class Widget::PlayButton : public Button {
|
||||||
|
public:
|
||||||
|
PlayButton(QWidget *parent);
|
||||||
|
|
||||||
|
void setState(PlayButtonLayout::State state) {
|
||||||
|
_layout.setState(state);
|
||||||
|
}
|
||||||
|
void finishTransform() {
|
||||||
|
_layout.finishTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
PlayButtonLayout _layout;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
Widget::PlayButton::PlayButton(QWidget *parent) : Button(parent)
|
||||||
|
, _layout(st::mediaPlayerButton, [this] { update(); }) {
|
||||||
|
resize(st::mediaPlayerButtonSize);
|
||||||
|
setCursor(style::cur_pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::PlayButton::paintEvent(QPaintEvent *e) {
|
||||||
|
Painter p(this);
|
||||||
|
|
||||||
|
p.translate(st::mediaPlayerButtonPosition.x(), st::mediaPlayerButtonPosition.y());
|
||||||
|
_layout.paint(p, st::mediaPlayerActiveFg);
|
||||||
|
}
|
||||||
|
|
||||||
Widget::Widget(QWidget *parent) : TWidget(parent)
|
Widget::Widget(QWidget *parent) : TWidget(parent)
|
||||||
, _shadow(st::defaultInnerDropdown.shadow)
|
, _nameLabel(this, st::mediaPlayerName)
|
||||||
, _cover(this) {
|
, _timeLabel(this, st::mediaPlayerTime)
|
||||||
_hideTimer.setSingleShot(true);
|
, _playPause(this)
|
||||||
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(onHideStart()));
|
, _volumeToggle(this, st::mediaPlayerVolumeToggle)
|
||||||
|
, _repeatTrack(this, st::mediaPlayerRepeatButton)
|
||||||
|
, _close(this, st::mediaPlayerClose)
|
||||||
|
, _shadow(this, st::shadowColor)
|
||||||
|
, _playback(new Ui::FilledSlider(this, st::mediaPlayerPlayback)) {
|
||||||
|
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||||
|
resize(st::wndMinWidth, st::mediaPlayerHeight + st::lineWidth);
|
||||||
|
|
||||||
_showTimer.setSingleShot(true);
|
_playback->setChangeProgressCallback([this](float64 value) {
|
||||||
connect(&_showTimer, SIGNAL(timeout()), this, SLOT(onShowStart()));
|
handleSeekProgress(value);
|
||||||
|
});
|
||||||
|
_playback->setChangeFinishedCallback([this](float64 value) {
|
||||||
|
handleSeekFinished(value);
|
||||||
|
});
|
||||||
|
_playPause->setClickedCallback([this] {
|
||||||
|
if (exists()) {
|
||||||
|
instance()->playPauseCancelClicked();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (_scroll) {
|
updateVolumeToggleIcon();
|
||||||
connect(_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
|
_volumeToggle->setClickedCallback([this] {
|
||||||
|
Global::SetSongVolume((Global::SongVolume() > 0) ? 0. : Global::RememberedSongVolume());
|
||||||
|
Global::RefSongVolumeChanged().notify();
|
||||||
|
});
|
||||||
|
subscribe(Global::RefSongVolumeChanged(), [this] { updateVolumeToggleIcon(); });
|
||||||
|
|
||||||
|
updateRepeatTrackIcon();
|
||||||
|
_repeatTrack->setClickedCallback([this] {
|
||||||
|
instance()->toggleRepeat();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (exists()) {
|
||||||
|
subscribe(instance()->repeatChangedNotifier(), [this] {
|
||||||
|
updateRepeatTrackIcon();
|
||||||
|
});
|
||||||
|
subscribe(instance()->playlistChangedNotifier(), [this] {
|
||||||
|
handlePlaylistUpdate();
|
||||||
|
});
|
||||||
|
subscribe(instance()->updatedNotifier(), [this](const UpdatedEvent &e) {
|
||||||
|
handleSongUpdate(e);
|
||||||
|
});
|
||||||
|
subscribe(instance()->songChangedNotifier(), [this] {
|
||||||
|
handleSongChange();
|
||||||
|
});
|
||||||
|
handleSongChange();
|
||||||
|
if (auto player = audioPlayer()) {
|
||||||
|
AudioMsgId playing;
|
||||||
|
auto playbackState = player->currentState(&playing, AudioMsgId::Type::Song);
|
||||||
|
handleSongUpdate(UpdatedEvent(&playing, &playbackState));
|
||||||
|
_playPause->finishTransform();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
void Widget::updateVolumeToggleIcon() {
|
||||||
if (isHidden() || _a_appearance.animating()) return false;
|
auto icon = []() -> const style::icon * {
|
||||||
|
auto volume = Global::SongVolume();
|
||||||
auto marginLeft = rtl() ? 0 : contentLeft();
|
if (volume > 0) {
|
||||||
auto marginRight = rtl() ? contentLeft() : 0;
|
if (volume < 1 / 3.) {
|
||||||
return rect().marginsRemoved(QMargins(marginLeft, 0, marginRight, st::mediaPlayerMarginBottom)).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
|
return &st::mediaPlayerVolumeIcon1;
|
||||||
|
} else if (volume < 2 / 3.) {
|
||||||
|
return &st::mediaPlayerVolumeIcon2;
|
||||||
|
}
|
||||||
|
return &st::mediaPlayerVolumeIcon3;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
};
|
||||||
|
_volumeToggle->setIcon(icon());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::onWindowActiveChanged() {
|
void Widget::setCloseCallback(CloseCallback &&callback) {
|
||||||
if (!App::wnd()->windowHandle()->isActive() && !isHidden()) {
|
_close->setClickedCallback(std_::move(callback));
|
||||||
leaveEvent(nullptr);
|
}
|
||||||
|
|
||||||
|
void Widget::setShadowGeometryToLeft(int x, int y, int w, int h) {
|
||||||
|
_shadow->setGeometryToLeft(x, y, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::showShadow() {
|
||||||
|
_shadow->show();
|
||||||
|
_playback->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::hideShadow() {
|
||||||
|
_shadow->hide();
|
||||||
|
_playback->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
QPoint Widget::getPositionForVolumeWidget() const {
|
||||||
|
auto x = _volumeToggle->x();
|
||||||
|
x += (_volumeToggle->width() - st::mediaPlayerVolumeSize.width()) / 2;
|
||||||
|
if (rtl()) x = width() - x - st::mediaPlayerVolumeSize.width();
|
||||||
|
return QPoint(x, height());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::volumeWidgetCreated(VolumeWidget *widget) {
|
||||||
|
_volumeToggle->installEventFilter(widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::handleSeekProgress(float64 progress) {
|
||||||
|
if (!_lastDurationMs) return;
|
||||||
|
|
||||||
|
auto positionMs = snap(static_cast<int64>(progress * _lastDurationMs), 0LL, _lastDurationMs);
|
||||||
|
if (_seekPositionMs != positionMs) {
|
||||||
|
_seekPositionMs = positionMs;
|
||||||
|
updateTimeLabel();
|
||||||
|
if (exists()) {
|
||||||
|
instance()->startSeeking();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::handleSeekFinished(float64 progress) {
|
||||||
|
if (!_lastDurationMs) return;
|
||||||
|
|
||||||
|
auto positionMs = snap(static_cast<int64>(progress * _lastDurationMs), 0LL, _lastDurationMs);
|
||||||
|
_seekPositionMs = -1;
|
||||||
|
|
||||||
|
AudioMsgId playing;
|
||||||
|
auto playbackState = audioPlayer()->currentState(&playing, AudioMsgId::Type::Song);
|
||||||
|
if (playing && playbackState.duration) {
|
||||||
|
audioPlayer()->seek(qRound(progress * playbackState.duration));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exists()) {
|
||||||
|
instance()->stopSeeking();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::resizeEvent(QResizeEvent *e) {
|
void Widget::resizeEvent(QResizeEvent *e) {
|
||||||
_cover->resize(width() - contentLeft(), st::mediaPlayerCoverHeight);
|
updatePlayPrevNextPositions();
|
||||||
_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<ScrolledWidget*>(_scroll->widget())) {
|
|
||||||
// widget->resizeToWidth(_scroll->width());
|
|
||||||
// onScroll();
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Widget::onScroll() {
|
auto right = st::mediaPlayerCloseRight;
|
||||||
//if (auto widget = static_cast<ScrolledWidget*>(_scroll->widget())) {
|
_close->moveToRight(right, st::mediaPlayerPlayTop); right += _close->width();
|
||||||
// int visibleTop = _scroll->scrollTop();
|
_repeatTrack->moveToRight(right, st::mediaPlayerPlayTop); right += _repeatTrack->width();
|
||||||
// int visibleBottom = visibleTop + _scroll->height();
|
_volumeToggle->moveToRight(right, st::mediaPlayerPlayTop); right += _volumeToggle->width();
|
||||||
// widget->setVisibleTopBottom(visibleTop, visibleBottom);
|
|
||||||
//}
|
updateLabelsGeometry();
|
||||||
|
|
||||||
|
_playback->setGeometry(0, height() - st::mediaPlayerPlayback.fullWidth, width(), st::mediaPlayerPlayback.fullWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::paintEvent(QPaintEvent *e) {
|
void Widget::paintEvent(QPaintEvent *e) {
|
||||||
Painter p(this);
|
Painter p(this);
|
||||||
|
auto fill = e->rect().intersected(QRect(0, 0, width(), st::mediaPlayerHeight));
|
||||||
|
if (!fill.isEmpty()) {
|
||||||
|
p.fillRect(fill, st::windowBg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!_cache.isNull()) {
|
void Widget::updatePlayPrevNextPositions() {
|
||||||
bool animating = _a_appearance.animating(getms());
|
auto left = st::mediaPlayerPlayLeft;
|
||||||
if (animating) {
|
auto top = st::mediaPlayerPlayTop;
|
||||||
p.setOpacity(_a_appearance.current(_hiding));
|
if (_previousTrack) {
|
||||||
} else if (_hiding) {
|
_previousTrack->moveToLeft(left, top); left += _previousTrack->width() + st::mediaPlayerPlaySkip;
|
||||||
hidingFinished();
|
_playPause->moveToLeft(left, top); left += _playPause->width() + st::mediaPlayerPlaySkip;
|
||||||
return;
|
_nextTrack->moveToLeft(left, top);
|
||||||
}
|
} else {
|
||||||
p.drawPixmap(0, 0, _cache);
|
_playPause->moveToLeft(left, top);
|
||||||
if (!animating) {
|
}
|
||||||
showChildren();
|
}
|
||||||
_cache = QPixmap();
|
|
||||||
}
|
void Widget::updateLabelsGeometry() {
|
||||||
|
auto left = st::mediaPlayerPlayLeft + _playPause->width();
|
||||||
|
if (_previousTrack) {
|
||||||
|
left += _previousTrack->width() + st::mediaPlayerPlaySkip + _nextTrack->width() + st::mediaPlayerPlaySkip;
|
||||||
|
}
|
||||||
|
left += st::mediaPlayerPadding;
|
||||||
|
|
||||||
|
auto right = st::mediaPlayerCloseRight + _close->width() + _repeatTrack->width() + _volumeToggle->width();
|
||||||
|
right += st::mediaPlayerPadding;
|
||||||
|
|
||||||
|
auto widthForName = width() - left - right;
|
||||||
|
widthForName -= _timeLabel->width() + 2 * st::normalFont->spacew;
|
||||||
|
_nameLabel->resizeToWidth(widthForName);
|
||||||
|
|
||||||
|
_nameLabel->moveToLeft(left, st::mediaPlayerNameTop - st::mediaPlayerName.font->ascent);
|
||||||
|
_timeLabel->moveToRight(right, st::mediaPlayerNameTop - st::mediaPlayerTime.font->ascent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::updateRepeatTrackIcon() {
|
||||||
|
_repeatTrack->setIcon(instance()->repeatEnabled() ? nullptr : &st::mediaPlayerRepeatDisabledIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::handleSongUpdate(const UpdatedEvent &e) {
|
||||||
|
auto &audioId = *e.audioId;
|
||||||
|
auto &playbackState = *e.playbackState;
|
||||||
|
if (!audioId || !audioId.audio()->song()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw shadow
|
_playback->updateState(*e.playbackState);
|
||||||
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) {
|
auto stopped = ((playbackState.state & AudioPlayerStoppedMask) || playbackState.state == AudioPlayerFinishing);
|
||||||
_hideTimer.stop();
|
auto showPause = !stopped && (playbackState.state == AudioPlayerPlaying || playbackState.state == AudioPlayerResuming || playbackState.state == AudioPlayerStarting);
|
||||||
if (_a_appearance.animating(getms())) {
|
if (exists() && instance()->isSeeking()) {
|
||||||
onShowStart();
|
showPause = true;
|
||||||
} else {
|
|
||||||
_showTimer.start(0);
|
|
||||||
}
|
}
|
||||||
return TWidget::enterEvent(e);
|
auto state = [audio = audioId.audio(), showPause] {
|
||||||
}
|
if (audio->loading()) {
|
||||||
|
return State::Cancel;
|
||||||
void Widget::leaveEvent(QEvent *e) {
|
} else if (showPause) {
|
||||||
_showTimer.stop();
|
return State::Pause;
|
||||||
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.animating()) {
|
|
||||||
showChildren();
|
|
||||||
_cache = myGrab(this);
|
|
||||||
}
|
|
||||||
hideChildren();
|
|
||||||
_a_appearance.start([this] {
|
|
||||||
update();
|
|
||||||
|
|
||||||
// hack, animating() call destroys lambda :(
|
|
||||||
auto that = this;
|
|
||||||
if (!_a_appearance.animating() && that->_hiding) {
|
|
||||||
that->_hiding = false;
|
|
||||||
that->hidingFinished();
|
|
||||||
}
|
}
|
||||||
}, from, to, st::defaultInnerDropdown.duration);
|
return State::Play;
|
||||||
|
};
|
||||||
|
_playPause->setState(state());
|
||||||
|
|
||||||
|
updateTimeText(audioId, playbackState);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::hidingFinished() {
|
void Widget::updateTimeText(const AudioMsgId &audioId, const AudioPlaybackState &playbackState) {
|
||||||
hide();
|
QString time;
|
||||||
showChildren();
|
qint64 position = 0, duration = 0, display = 0;
|
||||||
}
|
auto frequency = (playbackState.frequency ? playbackState.frequency : AudioVoiceMsgFrequency);
|
||||||
|
if (!(playbackState.state & AudioPlayerStoppedMask) && playbackState.state != AudioPlayerFinishing) {
|
||||||
int Widget::contentLeft() const {
|
display = position = playbackState.position;
|
||||||
return st::mediaPlayerMarginLeft;
|
duration = playbackState.duration;
|
||||||
}
|
} else {
|
||||||
|
display = playbackState.duration ? playbackState.duration : (audioId.audio()->song()->duration * frequency);
|
||||||
bool Widget::eventFilter(QObject *obj, QEvent *e) {
|
}
|
||||||
if (e->type() == QEvent::Enter) {
|
|
||||||
otherEnter();
|
_lastDurationMs = (playbackState.duration * 1000LL) / frequency;
|
||||||
} else if (e->type() == QEvent::Leave) {
|
|
||||||
otherLeave();
|
if (audioId.audio()->loading()) {
|
||||||
|
auto loaded = audioId.audio()->loadOffset();
|
||||||
|
auto loadProgress = snap(float64(loaded) / qMax(audioId.audio()->size, 1), 0., 1.);
|
||||||
|
_time = QString::number(qRound(loadProgress * 100)) + '%';
|
||||||
|
_playback->setDisabled(true);
|
||||||
|
} else {
|
||||||
|
display = display / frequency;
|
||||||
|
_time = formatDurationText(display);
|
||||||
|
_playback->setDisabled(false);
|
||||||
|
}
|
||||||
|
if (_seekPositionMs < 0) {
|
||||||
|
updateTimeLabel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::updateTimeLabel() {
|
||||||
|
auto timeLabelWidth = _timeLabel->width();
|
||||||
|
if (_seekPositionMs >= 0) {
|
||||||
|
auto playAlready = _seekPositionMs / 1000LL;
|
||||||
|
_timeLabel->setText(formatDurationText(playAlready));
|
||||||
|
} else {
|
||||||
|
_timeLabel->setText(_time);
|
||||||
|
}
|
||||||
|
if (timeLabelWidth != _timeLabel->width()) {
|
||||||
|
updateLabelsGeometry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::handleSongChange() {
|
||||||
|
auto ¤t = instance()->current();
|
||||||
|
auto song = current.audio()->song();
|
||||||
|
|
||||||
|
TextWithEntities textWithEntities;
|
||||||
|
if (song->performer.isEmpty()) {
|
||||||
|
textWithEntities.text = song->title.isEmpty() ? (current.audio()->name.isEmpty() ? qsl("Unknown Track") : current.audio()->name) : song->title;
|
||||||
|
} else {
|
||||||
|
auto title = song->title.isEmpty() ? qsl("Unknown Track") : textClean(song->title);
|
||||||
|
textWithEntities.text = song->performer + QString::fromUtf8(" \xe2\x80\x93 ") + title;
|
||||||
|
textWithEntities.entities.append({ EntityInTextBold, 0, song->performer.size(), QString() });
|
||||||
|
}
|
||||||
|
_nameLabel->setMarkedText(textWithEntities);
|
||||||
|
|
||||||
|
handlePlaylistUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::handlePlaylistUpdate() {
|
||||||
|
auto ¤t = instance()->current();
|
||||||
|
auto &playlist = instance()->playlist();
|
||||||
|
auto index = playlist.indexOf(current.contextId());
|
||||||
|
if (!current || index < 0) {
|
||||||
|
destroyPrevNextButtons();
|
||||||
|
} else {
|
||||||
|
createPrevNextButtons();
|
||||||
|
auto previousEnabled = (index > 0);
|
||||||
|
auto nextEnabled = (index + 1 < playlist.size());
|
||||||
|
_previousTrack->setIcon(previousEnabled ? nullptr : &st::mediaPlayerPreviousDisabledIcon);
|
||||||
|
_previousTrack->setCursor(previousEnabled ? style::cur_pointer : style::cur_default);
|
||||||
|
_nextTrack->setIcon(nextEnabled ? nullptr : &st::mediaPlayerNextDisabledIcon);
|
||||||
|
_nextTrack->setCursor(nextEnabled ? style::cur_pointer : style::cur_default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::createPrevNextButtons() {
|
||||||
|
if (!_previousTrack) {
|
||||||
|
_previousTrack.create(this, st::mediaPlayerPreviousButton);
|
||||||
|
_nextTrack.create(this, st::mediaPlayerNextButton);
|
||||||
|
_previousTrack->setClickedCallback([this]() {
|
||||||
|
if (exists()) {
|
||||||
|
instance()->previous();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_nextTrack->setClickedCallback([this]() {
|
||||||
|
if (exists()) {
|
||||||
|
instance()->next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
updatePlayPrevNextPositions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::destroyPrevNextButtons() {
|
||||||
|
if (_previousTrack) {
|
||||||
|
_previousTrack.destroy();
|
||||||
|
_nextTrack.destroy();
|
||||||
|
updatePlayPrevNextPositions();
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Player
|
} // namespace Player
|
||||||
|
|
|
@ -20,63 +20,79 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ui/effects/rect_shadow.h"
|
class AudioMsgId;
|
||||||
|
struct AudioPlaybackState;
|
||||||
|
class FlatLabel;
|
||||||
|
|
||||||
class ScrollArea;
|
namespace Ui {
|
||||||
|
class LabelSimple;
|
||||||
|
class IconButton;
|
||||||
|
class PlainShadow;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Media {
|
namespace Media {
|
||||||
|
namespace Clip {
|
||||||
|
class Playback;
|
||||||
|
} // namespace Clip
|
||||||
|
|
||||||
namespace Player {
|
namespace Player {
|
||||||
|
|
||||||
class CoverWidget;
|
class PlayButton;
|
||||||
class ListWidget;
|
class VolumeWidget;
|
||||||
|
struct UpdatedEvent;
|
||||||
|
|
||||||
class Widget : public TWidget, private base::Subscriber {
|
class Widget : public TWidget, private base::Subscriber {
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Widget(QWidget *parent);
|
Widget(QWidget *parent);
|
||||||
|
|
||||||
bool overlaps(const QRect &globalRect);
|
using CloseCallback = base::lambda_unique<void()>;
|
||||||
|
void setCloseCallback(CloseCallback &&callback);
|
||||||
|
|
||||||
void otherEnter();
|
void setShadowGeometryToLeft(int x, int y, int w, int h);
|
||||||
void otherLeave();
|
void showShadow();
|
||||||
|
void hideShadow();
|
||||||
|
|
||||||
|
QPoint getPositionForVolumeWidget() const;
|
||||||
|
void volumeWidgetCreated(VolumeWidget *widget);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
void paintEvent(QPaintEvent *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:
|
private:
|
||||||
void hidingFinished();
|
void handleSeekProgress(float64 progress);
|
||||||
int contentLeft() const;
|
void handleSeekFinished(float64 progress);
|
||||||
int contentWidth() const {
|
|
||||||
return width() - contentLeft();
|
|
||||||
}
|
|
||||||
|
|
||||||
void startAnimation();
|
void updatePlayPrevNextPositions();
|
||||||
|
void updateLabelsGeometry();
|
||||||
|
void updateRepeatTrackIcon();
|
||||||
|
void createPrevNextButtons();
|
||||||
|
void destroyPrevNextButtons();
|
||||||
|
|
||||||
bool _hiding = false;
|
void updateVolumeToggleIcon();
|
||||||
|
|
||||||
QPixmap _cache;
|
void handleSongUpdate(const UpdatedEvent &e);
|
||||||
FloatAnimation _a_appearance;
|
void handleSongChange();
|
||||||
|
void handlePlaylistUpdate();
|
||||||
|
|
||||||
QTimer _hideTimer, _showTimer;
|
void updateTimeText(const AudioMsgId &audioId, const AudioPlaybackState &playbackState);
|
||||||
|
void updateTimeLabel();
|
||||||
|
|
||||||
Ui::RectShadow _shadow;
|
int64 _seekPositionMs = -1;
|
||||||
ChildWidget<CoverWidget> _cover;
|
int64 _lastDurationMs = 0;
|
||||||
ChildWidget<ListWidget> _list = { nullptr };
|
QString _time;
|
||||||
ChildWidget<ScrollArea> _scroll = { nullptr };
|
|
||||||
|
|
||||||
|
class PlayButton;
|
||||||
|
ChildWidget<FlatLabel> _nameLabel;
|
||||||
|
ChildWidget<Ui::LabelSimple> _timeLabel;
|
||||||
|
ChildWidget<Ui::IconButton> _previousTrack = { nullptr };
|
||||||
|
ChildWidget<PlayButton> _playPause;
|
||||||
|
ChildWidget<Ui::IconButton> _nextTrack = { nullptr };
|
||||||
|
ChildWidget<Ui::IconButton> _volumeToggle;
|
||||||
|
ChildWidget<Ui::IconButton> _repeatTrack;
|
||||||
|
ChildWidget<Ui::IconButton> _close;
|
||||||
|
ChildWidget<Ui::PlainShadow> _shadow = { nullptr };
|
||||||
|
ChildWidget<Clip::Playback> _playback;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "media/view/media_clip_volume_controller.h"
|
#include "media/view/media_clip_volume_controller.h"
|
||||||
#include "styles/style_mediaview.h"
|
#include "styles/style_mediaview.h"
|
||||||
#include "ui/widgets/label_simple.h"
|
#include "ui/widgets/label_simple.h"
|
||||||
|
#include "ui/widgets/media_slider.h"
|
||||||
#include "ui/effects/fade_animation.h"
|
#include "ui/effects/fade_animation.h"
|
||||||
#include "ui/buttons/icon_button.h"
|
#include "ui/buttons/icon_button.h"
|
||||||
#include "media/media_audio.h"
|
#include "media/media_audio.h"
|
||||||
|
@ -34,7 +35,7 @@ namespace Clip {
|
||||||
|
|
||||||
Controller::Controller(QWidget *parent) : TWidget(parent)
|
Controller::Controller(QWidget *parent) : TWidget(parent)
|
||||||
, _playPauseResume(this, st::mediaviewPlayButton)
|
, _playPauseResume(this, st::mediaviewPlayButton)
|
||||||
, _playback(this, st::mediaviewPlayback)
|
, _playback(new Ui::MediaSlider(this, st::mediaviewPlayback))
|
||||||
, _volumeController(this)
|
, _volumeController(this)
|
||||||
, _fullScreenToggle(this, st::mediaviewFullScreenButton)
|
, _fullScreenToggle(this, st::mediaviewFullScreenButton)
|
||||||
, _playedAlready(this, st::mediaviewPlayProgressLabel)
|
, _playedAlready(this, st::mediaviewPlayProgressLabel)
|
||||||
|
|
|
@ -22,13 +22,12 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "media/view/media_clip_playback.h"
|
#include "media/view/media_clip_playback.h"
|
||||||
|
|
||||||
#include "styles/style_mediaview.h"
|
#include "styles/style_mediaview.h"
|
||||||
#include "ui/widgets/media_slider.h"
|
|
||||||
#include "media/media_audio.h"
|
#include "media/media_audio.h"
|
||||||
|
|
||||||
namespace Media {
|
namespace Media {
|
||||||
namespace Clip {
|
namespace Clip {
|
||||||
|
|
||||||
Playback::Playback(QWidget *parent, const style::MediaSlider &st) : _slider(new Ui::MediaSlider(parent, st)) {
|
Playback::Playback(Ui::ContinuousSlider *slider) : _slider(slider) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Playback::updateState(const AudioPlaybackState &playbackState) {
|
void Playback::updateState(const AudioPlaybackState &playbackState) {
|
||||||
|
|
|
@ -20,32 +20,26 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ui/widgets/media_slider.h"
|
#include "ui/widgets/continuous_slider.h"
|
||||||
|
|
||||||
struct AudioPlaybackState;
|
struct AudioPlaybackState;
|
||||||
namespace style {
|
|
||||||
struct MediaSlider;
|
|
||||||
} // namespace style
|
|
||||||
namespace Ui {
|
|
||||||
class MediaSlider;
|
|
||||||
} // namespace Ui
|
|
||||||
|
|
||||||
namespace Media {
|
namespace Media {
|
||||||
namespace Clip {
|
namespace Clip {
|
||||||
|
|
||||||
class Playback {
|
class Playback {
|
||||||
public:
|
public:
|
||||||
Playback(QWidget *parent, const style::MediaSlider &st);
|
Playback(Ui::ContinuousSlider *slider);
|
||||||
|
|
||||||
void updateState(const AudioPlaybackState &playbackState);
|
void updateState(const AudioPlaybackState &playbackState);
|
||||||
|
|
||||||
void setFadeOpacity(float64 opacity) {
|
void setFadeOpacity(float64 opacity) {
|
||||||
_slider->setFadeOpacity(opacity);
|
_slider->setFadeOpacity(opacity);
|
||||||
}
|
}
|
||||||
void setChangeProgressCallback(Ui::MediaSlider::Callback &&callback) {
|
void setChangeProgressCallback(Ui::ContinuousSlider::Callback &&callback) {
|
||||||
_slider->setChangeProgressCallback(std_::move(callback));
|
_slider->setChangeProgressCallback(std_::move(callback));
|
||||||
}
|
}
|
||||||
void setChangeFinishedCallback(Ui::MediaSlider::Callback &&callback) {
|
void setChangeFinishedCallback(Ui::ContinuousSlider::Callback &&callback) {
|
||||||
_slider->setChangeFinishedCallback(std_::move(callback));
|
_slider->setChangeFinishedCallback(std_::move(callback));
|
||||||
}
|
}
|
||||||
void setGeometry(int x, int y, int w, int h) {
|
void setGeometry(int x, int y, int w, int h) {
|
||||||
|
@ -68,7 +62,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::MediaSlider *_slider;
|
Ui::ContinuousSlider *_slider;
|
||||||
|
|
||||||
int64 _position = 0;
|
int64 _position = 0;
|
||||||
int64 _duration = 0;
|
int64 _duration = 0;
|
||||||
|
|
|
@ -792,7 +792,7 @@ void MediaView::onDocClick() {
|
||||||
if (_doc->loading()) {
|
if (_doc->loading()) {
|
||||||
onSaveCancel();
|
onSaveCancel();
|
||||||
} else {
|
} else {
|
||||||
DocumentOpenClickHandler::doOpen(_doc, ActionOnLoadNone);
|
DocumentOpenClickHandler::doOpen(_doc, nullptr, ActionOnLoadNone);
|
||||||
if (_doc->loading() && !_radial.animating()) {
|
if (_doc->loading() && !_radial.animating()) {
|
||||||
_radial.start(_doc->progress());
|
_radial.start(_doc->progress());
|
||||||
}
|
}
|
||||||
|
@ -1477,7 +1477,7 @@ void MediaView::onVideoSeekFinished(int64 positionMs) {
|
||||||
|
|
||||||
void MediaView::onVideoVolumeChanged(float64 volume) {
|
void MediaView::onVideoVolumeChanged(float64 volume) {
|
||||||
Global::SetVideoVolume(volume);
|
Global::SetVideoVolume(volume);
|
||||||
emit audioPlayer()->videoVolumeChanged();
|
Global::RefVideoVolumeChanged().notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaView::onVideoToggleFullScreen() {
|
void MediaView::onVideoToggleFullScreen() {
|
||||||
|
|
|
@ -61,23 +61,14 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
FileLoader::FileLoader(const QString &toFile, int32 size, LocationType locationType, LoadToCacheSetting toCache, LoadFromCloudSetting fromCloud, bool autoLoading)
|
FileLoader::FileLoader(const QString &toFile, int32 size, LocationType locationType, LoadToCacheSetting toCache, LoadFromCloudSetting fromCloud, bool autoLoading)
|
||||||
: _prev(0)
|
: _autoLoading(autoLoading)
|
||||||
, _next(0)
|
|
||||||
, _priority(0)
|
|
||||||
, _paused(false)
|
|
||||||
, _autoLoading(autoLoading)
|
|
||||||
, _inQueue(false)
|
|
||||||
, _complete(false)
|
|
||||||
, _localStatus(LocalNotTried)
|
|
||||||
, _file(toFile)
|
, _file(toFile)
|
||||||
, _fname(toFile)
|
, _fname(toFile)
|
||||||
, _fileIsOpen(false)
|
|
||||||
, _toCache(toCache)
|
, _toCache(toCache)
|
||||||
, _fromCloud(fromCloud)
|
, _fromCloud(fromCloud)
|
||||||
, _size(size)
|
, _size(size)
|
||||||
, _type(mtpc_storage_fileUnknown)
|
, _type(mtpc_storage_fileUnknown)
|
||||||
, _locationType(locationType)
|
, _locationType(locationType) {
|
||||||
, _localTaskId(0) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray FileLoader::imageFormat(const QSize &shrinkBox) const {
|
QByteArray FileLoader::imageFormat(const QSize &shrinkBox) const {
|
||||||
|
@ -124,7 +115,9 @@ int32 FileLoader::fullSize() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileLoader::setFileName(const QString &fileName) {
|
bool FileLoader::setFileName(const QString &fileName) {
|
||||||
if (_toCache != LoadToCacheAsWell || !_fname.isEmpty()) return fileName.isEmpty();
|
if (_toCache != LoadToCacheAsWell || !_fname.isEmpty()) {
|
||||||
|
return fileName.isEmpty() || (fileName == _fname);
|
||||||
|
}
|
||||||
_fname = fileName;
|
_fname = fileName;
|
||||||
_file.setFileName(_fname);
|
_file.setFileName(_fname);
|
||||||
return true;
|
return true;
|
||||||
|
@ -591,6 +584,7 @@ bool mtpFileLoader::tryLoadLocal() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
emit progress(this);
|
||||||
|
|
||||||
if (_localStatus != LocalNotTried) {
|
if (_localStatus != LocalNotTried) {
|
||||||
return _complete;
|
return _complete;
|
||||||
|
|
|
@ -182,12 +182,16 @@ signals:
|
||||||
protected:
|
protected:
|
||||||
void readImage(const QSize &shrinkBox) const;
|
void readImage(const QSize &shrinkBox) const;
|
||||||
|
|
||||||
FileLoader *_prev, *_next;
|
FileLoader *_prev = nullptr;
|
||||||
int32 _priority;
|
FileLoader *_next = nullptr;
|
||||||
|
int _priority = 0;
|
||||||
FileLoaderQueue *_queue;
|
FileLoaderQueue *_queue;
|
||||||
|
|
||||||
bool _paused, _autoLoading, _inQueue, _complete;
|
bool _paused = false;
|
||||||
mutable LocalLoadStatus _localStatus;
|
bool _autoLoading = false;
|
||||||
|
bool _inQueue = false;
|
||||||
|
bool _complete = false;
|
||||||
|
mutable LocalLoadStatus _localStatus = LocalNotTried;
|
||||||
|
|
||||||
virtual bool tryLoadLocal() = 0;
|
virtual bool tryLoadLocal() = 0;
|
||||||
virtual void cancelRequests() = 0;
|
virtual void cancelRequests() = 0;
|
||||||
|
@ -201,7 +205,7 @@ protected:
|
||||||
|
|
||||||
QFile _file;
|
QFile _file;
|
||||||
QString _fname;
|
QString _fname;
|
||||||
bool _fileIsOpen;
|
bool _fileIsOpen = false;
|
||||||
|
|
||||||
LoadToCacheSetting _toCache;
|
LoadToCacheSetting _toCache;
|
||||||
LoadFromCloudSetting _fromCloud;
|
LoadFromCloudSetting _fromCloud;
|
||||||
|
@ -212,7 +216,7 @@ protected:
|
||||||
mtpTypeId _type;
|
mtpTypeId _type;
|
||||||
LocationType _locationType;
|
LocationType _locationType;
|
||||||
|
|
||||||
TaskId _localTaskId;
|
TaskId _localTaskId = 0;
|
||||||
mutable QByteArray _imageFormat;
|
mutable QByteArray _imageFormat;
|
||||||
mutable QPixmap _imagePixmap;
|
mutable QPixmap _imagePixmap;
|
||||||
|
|
||||||
|
|
|
@ -37,8 +37,8 @@ using AllUpdatesList = QMap<PeerData*, PeerUpdate>;
|
||||||
NeverFreedPointer<AllUpdatesList> AllUpdates;
|
NeverFreedPointer<AllUpdatesList> AllUpdates;
|
||||||
|
|
||||||
void StartCallback() {
|
void StartCallback() {
|
||||||
SmallUpdates.makeIfNull();
|
SmallUpdates.createIfNull();
|
||||||
AllUpdates.makeIfNull();
|
AllUpdates.createIfNull();
|
||||||
}
|
}
|
||||||
void FinishCallback() {
|
void FinishCallback() {
|
||||||
SmallUpdates.clear();
|
SmallUpdates.clear();
|
||||||
|
@ -63,8 +63,8 @@ void mergePeerUpdate(PeerUpdate &mergeTo, const PeerUpdate &mergeFrom) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void peerUpdatedDelayed(const PeerUpdate &update) {
|
void peerUpdatedDelayed(const PeerUpdate &update) {
|
||||||
SmallUpdates.makeIfNull();
|
SmallUpdates.createIfNull();
|
||||||
AllUpdates.makeIfNull();
|
AllUpdates.createIfNull();
|
||||||
|
|
||||||
Global::RefHandleDelayedPeerUpdates().call();
|
Global::RefHandleDelayedPeerUpdates().call();
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "fileuploader.h"
|
#include "fileuploader.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "playerwidget.h"
|
|
||||||
#include "media/media_audio.h"
|
#include "media/media_audio.h"
|
||||||
#include "media/player/media_player_instance.h"
|
#include "media/player/media_player_instance.h"
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
|
|
|
@ -32,9 +32,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "overviewwidget.h"
|
#include "overviewwidget.h"
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "playerwidget.h"
|
|
||||||
#include "overview/overview_layout.h"
|
#include "overview/overview_layout.h"
|
||||||
#include "history/history_media_types.h"
|
#include "history/history_media_types.h"
|
||||||
|
#include "media/media_audio.h"
|
||||||
|
|
||||||
// flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html
|
// flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html
|
||||||
|
|
||||||
|
@ -1903,13 +1903,8 @@ OverviewInner::~OverviewInner() {
|
||||||
OverviewWidget::OverviewWidget(QWidget *parent, PeerData *peer, MediaOverviewType type) : TWidget(parent)
|
OverviewWidget::OverviewWidget(QWidget *parent, PeerData *peer, MediaOverviewType type) : TWidget(parent)
|
||||||
, _scroll(this, st::historyScroll, false)
|
, _scroll(this, st::historyScroll, false)
|
||||||
, _inner(this, &_scroll, peer, type)
|
, _inner(this, &_scroll, peer, type)
|
||||||
, _noDropResizeIndex(false)
|
|
||||||
, _a_show(animation(this, &OverviewWidget::step_show))
|
, _a_show(animation(this, &OverviewWidget::step_show))
|
||||||
, _scrollSetAfterShow(0)
|
, _topShadow(this, st::shadowColor) {
|
||||||
, _scrollDelta(0)
|
|
||||||
, _selCount(0)
|
|
||||||
, _topShadow(this, st::shadowColor)
|
|
||||||
, _inGrab(false) {
|
|
||||||
_scroll.setFocusPolicy(Qt::NoFocus);
|
_scroll.setFocusPolicy(Qt::NoFocus);
|
||||||
_scroll.setWidget(&_inner);
|
_scroll.setWidget(&_inner);
|
||||||
_scroll.move(0, 0);
|
_scroll.move(0, 0);
|
||||||
|
@ -1923,8 +1918,6 @@ OverviewWidget::OverviewWidget(QWidget *parent, PeerData *peer, MediaOverviewTyp
|
||||||
connect(&_scrollTimer, SIGNAL(timeout()), this, SLOT(onScrollTimer()));
|
connect(&_scrollTimer, SIGNAL(timeout()), this, SLOT(onScrollTimer()));
|
||||||
_scrollTimer.setSingleShot(false);
|
_scrollTimer.setSingleShot(false);
|
||||||
|
|
||||||
// connect(App::main()->player(), SIGNAL(playerSongChanged(const FullMsgId&)), this, SLOT(onPlayerSongChanged(const FullMsgId&)));
|
|
||||||
|
|
||||||
switchType(type);
|
switchType(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1963,8 +1956,8 @@ void OverviewWidget::resizeEvent(QResizeEvent *e) {
|
||||||
}
|
}
|
||||||
_noDropResizeIndex = false;
|
_noDropResizeIndex = false;
|
||||||
|
|
||||||
_topShadow.resize(width() - ((!Adaptive::OneColumn() && !_inGrab) ? st::lineWidth : 0), st::lineWidth);
|
_topShadow->resize(width() - ((!Adaptive::OneColumn() && !_inGrab) ? st::lineWidth : 0), st::lineWidth);
|
||||||
_topShadow.moveToLeft((!Adaptive::OneColumn() && !_inGrab) ? st::lineWidth : 0, 0);
|
_topShadow->moveToLeft((!Adaptive::OneColumn() && !_inGrab) ? st::lineWidth : 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OverviewWidget::paintEvent(QPaintEvent *e) {
|
void OverviewWidget::paintEvent(QPaintEvent *e) {
|
||||||
|
@ -2129,9 +2122,9 @@ void OverviewWidget::showAnimated(Window::SlideDirection direction, const Window
|
||||||
|
|
||||||
_cacheUnder = params.oldContentCache;
|
_cacheUnder = params.oldContentCache;
|
||||||
show();
|
show();
|
||||||
_topShadow.setVisible(params.withTopBarShadow ? false : true);
|
_topShadow->setVisible(params.withTopBarShadow ? false : true);
|
||||||
_cacheOver = App::main()->grabForShowAnimation(params);
|
_cacheOver = App::main()->grabForShowAnimation(params);
|
||||||
_topShadow.setVisible(params.withTopBarShadow ? true : false);
|
_topShadow->setVisible(params.withTopBarShadow ? true : false);
|
||||||
App::main()->topBar()->startAnim();
|
App::main()->topBar()->startAnim();
|
||||||
|
|
||||||
_scrollSetAfterShow = _scroll.scrollTop();
|
_scrollSetAfterShow = _scroll.scrollTop();
|
||||||
|
@ -2159,7 +2152,7 @@ void OverviewWidget::step_show(float64 ms, bool timer) {
|
||||||
float64 dt = ms / st::slideDuration;
|
float64 dt = ms / st::slideDuration;
|
||||||
if (dt >= 1) {
|
if (dt >= 1) {
|
||||||
_a_show.stop();
|
_a_show.stop();
|
||||||
_topShadow.show();
|
_topShadow->show();
|
||||||
|
|
||||||
a_coordUnder.finish();
|
a_coordUnder.finish();
|
||||||
a_coordOver.finish();
|
a_coordOver.finish();
|
||||||
|
@ -2202,6 +2195,17 @@ void OverviewWidget::changingMsgId(HistoryItem *row, MsgId newId) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OverviewWidget::grapWithoutTopBarShadow() {
|
||||||
|
grabStart();
|
||||||
|
_topShadow->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverviewWidget::grabFinish() {
|
||||||
|
_inGrab = false;
|
||||||
|
resizeEvent(0);
|
||||||
|
_topShadow->show();
|
||||||
|
}
|
||||||
|
|
||||||
void OverviewWidget::ui_repaintHistoryItem(const HistoryItem *item) {
|
void OverviewWidget::ui_repaintHistoryItem(const HistoryItem *item) {
|
||||||
if (peer() == item->history()->peer || migratePeer() == item->history()->peer) {
|
if (peer() == item->history()->peer || migratePeer() == item->history()->peer) {
|
||||||
_inner.repaintItem(item);
|
_inner.repaintItem(item);
|
||||||
|
@ -2263,15 +2267,6 @@ void OverviewWidget::onScrollTimer() {
|
||||||
_scroll.scrollToY(_scroll.scrollTop() + d);
|
_scroll.scrollToY(_scroll.scrollTop() + d);
|
||||||
}
|
}
|
||||||
|
|
||||||
//void OverviewWidget::onPlayerSongChanged(const FullMsgId &msgId) {
|
|
||||||
// if (type() == OverviewMusicFiles) {
|
|
||||||
// int32 top = _inner.itemTop(msgId);
|
|
||||||
// if (top > 0) {
|
|
||||||
// _scroll.scrollToY(snap(top - int(_scroll.height() - (st::msgPadding.top() + st::mediaThumbSize + st::msgPadding.bottom())) / 2, 0, _scroll.scrollTopMax()));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
void OverviewWidget::checkSelectingScroll(QPoint point) {
|
void OverviewWidget::checkSelectingScroll(QPoint point) {
|
||||||
if (point.y() < _scroll.scrollTop()) {
|
if (point.y() < _scroll.scrollTop()) {
|
||||||
_scrollDelta = point.y() - _scroll.scrollTop();
|
_scrollDelta = point.y() - _scroll.scrollTop();
|
||||||
|
|
|
@ -25,20 +25,21 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
namespace Overview {
|
namespace Overview {
|
||||||
namespace Layout {
|
namespace Layout {
|
||||||
|
|
||||||
class AbstractItem;
|
class AbstractItem;
|
||||||
class ItemBase;
|
class ItemBase;
|
||||||
class Date;
|
class Date;
|
||||||
|
|
||||||
} // namespace Layout
|
} // namespace Layout
|
||||||
} // namespace Overview
|
} // namespace Overview
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class PlainShadow;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
class OverviewWidget;
|
class OverviewWidget;
|
||||||
class OverviewInner : public QWidget, public AbstractTooltipShower, public RPCSender, private base::Subscriber {
|
class OverviewInner : public QWidget, public AbstractTooltipShower, public RPCSender, private base::Subscriber {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
OverviewInner(OverviewWidget *overview, ScrollArea *scroll, PeerData *peer, MediaOverviewType type);
|
OverviewInner(OverviewWidget *overview, ScrollArea *scroll, PeerData *peer, MediaOverviewType type);
|
||||||
|
|
||||||
void activate();
|
void activate();
|
||||||
|
@ -96,7 +97,6 @@ public:
|
||||||
~OverviewInner();
|
~OverviewInner();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void onUpdateSelected();
|
void onUpdateSelected();
|
||||||
|
|
||||||
void copyContextUrl();
|
void copyContextUrl();
|
||||||
|
@ -123,7 +123,6 @@ public slots:
|
||||||
void onNeedSearchMessages();
|
void onNeedSearchMessages();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
MsgId complexMsgId(const HistoryItem *item) const;
|
MsgId complexMsgId(const HistoryItem *item) const;
|
||||||
|
|
||||||
bool itemMigrated(MsgId msgId) const;
|
bool itemMigrated(MsgId msgId) const;
|
||||||
|
@ -253,7 +252,6 @@ class OverviewWidget : public TWidget, public RPCSender {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
OverviewWidget(QWidget *parent, PeerData *peer, MediaOverviewType type);
|
OverviewWidget(QWidget *parent, PeerData *peer, MediaOverviewType type);
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
@ -309,15 +307,8 @@ public:
|
||||||
_inGrab = true;
|
_inGrab = true;
|
||||||
resizeEvent(0);
|
resizeEvent(0);
|
||||||
}
|
}
|
||||||
void grapWithoutTopBarShadow() {
|
void grapWithoutTopBarShadow();
|
||||||
grabStart();
|
void grabFinish() override;
|
||||||
_topShadow.hide();
|
|
||||||
}
|
|
||||||
void grabFinish() override {
|
|
||||||
_inGrab = false;
|
|
||||||
resizeEvent(0);
|
|
||||||
_topShadow.show();
|
|
||||||
}
|
|
||||||
void rpcClear() override {
|
void rpcClear() override {
|
||||||
_inner.rpcClear();
|
_inner.rpcClear();
|
||||||
RPCSender::rpcClear();
|
RPCSender::rpcClear();
|
||||||
|
@ -330,12 +321,10 @@ public:
|
||||||
~OverviewWidget();
|
~OverviewWidget();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void activate();
|
void activate();
|
||||||
void onScroll();
|
void onScroll();
|
||||||
|
|
||||||
void onScrollTimer();
|
void onScrollTimer();
|
||||||
// void onPlayerSongChanged(const FullMsgId &msgId);
|
|
||||||
|
|
||||||
void onForwardSelected();
|
void onForwardSelected();
|
||||||
void onDeleteSelected();
|
void onDeleteSelected();
|
||||||
|
@ -344,10 +333,9 @@ public slots:
|
||||||
void onClearSelected();
|
void onClearSelected();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
ScrollArea _scroll;
|
ScrollArea _scroll;
|
||||||
OverviewInner _inner;
|
OverviewInner _inner;
|
||||||
bool _noDropResizeIndex;
|
bool _noDropResizeIndex = false;
|
||||||
|
|
||||||
QString _header;
|
QString _header;
|
||||||
|
|
||||||
|
@ -356,15 +344,15 @@ private:
|
||||||
anim::ivalue a_coordUnder, a_coordOver;
|
anim::ivalue a_coordUnder, a_coordOver;
|
||||||
anim::fvalue a_progress;
|
anim::fvalue a_progress;
|
||||||
|
|
||||||
int32 _scrollSetAfterShow;
|
int32 _scrollSetAfterShow = 0;
|
||||||
|
|
||||||
QTimer _scrollTimer;
|
QTimer _scrollTimer;
|
||||||
int32 _scrollDelta;
|
int32 _scrollDelta = 0;
|
||||||
|
|
||||||
int32 _selCount;
|
int32 _selCount = 0;
|
||||||
|
|
||||||
PlainShadow _topShadow;
|
ChildWidget<Ui::PlainShadow> _topShadow;
|
||||||
bool _inGrab;
|
bool _inGrab = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -214,7 +214,7 @@ using Notification = QSharedPointer<NotificationData>;
|
||||||
void start() {
|
void start() {
|
||||||
if (LibNotifyLoaded()) {
|
if (LibNotifyLoaded()) {
|
||||||
if (Libs::notify_is_initted() || Libs::notify_init("Telegram Desktop")) {
|
if (Libs::notify_is_initted() || Libs::notify_init("Telegram Desktop")) {
|
||||||
ManagerInstance.makeIfNull();
|
ManagerInstance.createIfNull();
|
||||||
if (!ManagerInstance->init()) {
|
if (!ManagerInstance->init()) {
|
||||||
ManagerInstance.clear();
|
ManagerInstance.clear();
|
||||||
LOG(("LibNotify Error: manager failed to init!"));
|
LOG(("LibNotify Error: manager failed to init!"));
|
||||||
|
|
|
@ -21,7 +21,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "playerwidget.h"
|
|
||||||
#include "historywidget.h"
|
#include "historywidget.h"
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
#include "window/notifications_manager_default.h"
|
#include "window/notifications_manager_default.h"
|
||||||
|
|
|
@ -96,7 +96,7 @@ namespace Notifications {
|
||||||
|
|
||||||
void start() {
|
void start() {
|
||||||
if (cPlatform() != dbipMacOld) {
|
if (cPlatform() != dbipMacOld) {
|
||||||
ManagerInstance.makeIfNull();
|
ManagerInstance.createIfNull();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -316,7 +316,7 @@ private:
|
||||||
|
|
||||||
void start() {
|
void start() {
|
||||||
if (init()) {
|
if (init()) {
|
||||||
ManagerInstance.makeIfNull();
|
ManagerInstance.createIfNull();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,695 +0,0 @@
|
||||||
/*
|
|
||||||
This file is part of Telegram Desktop,
|
|
||||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
|
||||||
|
|
||||||
Telegram Desktop 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 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
It 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.
|
|
||||||
|
|
||||||
In addition, as a special exception, the copyright holders give permission
|
|
||||||
to link the code of portions of this program with the OpenSSL library.
|
|
||||||
|
|
||||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
|
||||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|
||||||
*/
|
|
||||||
#include "stdafx.h"
|
|
||||||
#include "playerwidget.h"
|
|
||||||
|
|
||||||
#include "shortcuts.h"
|
|
||||||
#include "lang.h"
|
|
||||||
#include "boxes/addcontactbox.h"
|
|
||||||
#include "application.h"
|
|
||||||
#include "mainwindow.h"
|
|
||||||
#include "playerwidget.h"
|
|
||||||
#include "mainwidget.h"
|
|
||||||
#include "localstorage.h"
|
|
||||||
#include "media/media_audio.h"
|
|
||||||
#include "history/history_media_types.h"
|
|
||||||
|
|
||||||
PlayerWidget::PlayerWidget(QWidget *parent) : TWidget(parent)
|
|
||||||
, _a_state(animation(this, &PlayerWidget::step_state))
|
|
||||||
, _a_progress(animation(this, &PlayerWidget::step_progress)) {
|
|
||||||
resize(st::wndMinWidth, st::playerHeight);
|
|
||||||
setMouseTracking(true);
|
|
||||||
memset(_stateHovers, 0, sizeof(_stateHovers));
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::paintEvent(QPaintEvent *e) {
|
|
||||||
Painter p(this);
|
|
||||||
|
|
||||||
QRect r(e->rect()), checkr(myrtlrect(r));
|
|
||||||
p.fillRect(r, st::playerBg->b);
|
|
||||||
|
|
||||||
if (!_playbackRect.contains(checkr)) {
|
|
||||||
if (_fullAvailable && checkr.intersects(_prevRect)) {
|
|
||||||
if (_prevAvailable) {
|
|
||||||
float64 o = _stateHovers[OverPrev];
|
|
||||||
p.setOpacity(o * 1. + (1. - o) * st::playerInactiveOpacity);
|
|
||||||
} else {
|
|
||||||
p.setOpacity(st::playerUnavailableOpacity);
|
|
||||||
}
|
|
||||||
p.drawSpriteCenterLeft(_prevRect, width(), st::playerPrev);
|
|
||||||
}
|
|
||||||
if (checkr.intersects(_playRect)) {
|
|
||||||
float64 o = _stateHovers[OverPlay];
|
|
||||||
p.setOpacity(o * 1. + (1. - o) * st::playerInactiveOpacity);
|
|
||||||
p.drawSpriteCenterLeft(_playRect, width(), (_showPause || _down == OverPlayback) ? st::playerPause : st::playerPlay);
|
|
||||||
}
|
|
||||||
if (_fullAvailable && checkr.intersects(_nextRect)) {
|
|
||||||
if (_nextAvailable) {
|
|
||||||
float64 o = _stateHovers[OverNext];
|
|
||||||
p.setOpacity(o * 1. + (1. - o) * st::playerInactiveOpacity);
|
|
||||||
} else {
|
|
||||||
p.setOpacity(st::playerUnavailableOpacity);
|
|
||||||
}
|
|
||||||
p.drawSpriteCenterLeft(_nextRect, width(), st::playerNext);
|
|
||||||
}
|
|
||||||
if (checkr.intersects(_closeRect)) {
|
|
||||||
float64 o = _stateHovers[OverClose];
|
|
||||||
p.setOpacity(o * 1. + (1. - o) * st::playerInactiveOpacity);
|
|
||||||
p.drawSpriteCenterLeft(_closeRect, width(), st::playerClose);
|
|
||||||
}
|
|
||||||
if (checkr.intersects(_volumeRect)) {
|
|
||||||
float64 o = _stateHovers[OverVolume];
|
|
||||||
p.setOpacity(o * 1. + (1. - o) * st::playerInactiveOpacity);
|
|
||||||
int32 top = _volumeRect.y() + (_volumeRect.height() - st::playerVolume.pxHeight()) / 2;
|
|
||||||
int32 left = _volumeRect.x() + (_volumeRect.width() - st::playerVolume.pxWidth()) / 2;
|
|
||||||
int32 mid = left + qRound(st::playerVolume.pxWidth() * Global::SongVolume());
|
|
||||||
int32 right = left + st::playerVolume.pxWidth();
|
|
||||||
if (rtl()) {
|
|
||||||
left = width() - left;
|
|
||||||
mid = width() - mid;
|
|
||||||
right = width() - right;
|
|
||||||
if (mid < left) {
|
|
||||||
p.drawPixmap(QRect(mid, top, left - mid, st::playerVolume.pxHeight()), App::sprite(), QRect(st::playerVolume.rect().x() + (mid - right) * cIntRetinaFactor(), st::playerVolume.rect().y(), (left - mid) * cIntRetinaFactor(), st::playerVolume.pxHeight() * cIntRetinaFactor()));
|
|
||||||
}
|
|
||||||
if (right < mid) {
|
|
||||||
p.setOpacity(st::playerUnavailableOpacity);
|
|
||||||
p.drawPixmap(QRect(right, top, mid - right, st::playerVolume.pxHeight()), App::sprite(), QRect(st::playerVolume.rect().x(), st::playerVolume.rect().y(), (mid - right) * cIntRetinaFactor(), st::playerVolume.pxHeight() * cIntRetinaFactor()));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (mid > left) {
|
|
||||||
p.drawPixmap(QRect(left, top, mid - left, st::playerVolume.pxHeight()), App::sprite(), QRect(st::playerVolume.rect().x(), st::playerVolume.rect().y(), (mid - left) * cIntRetinaFactor(), st::playerVolume.pxHeight() * cIntRetinaFactor()));
|
|
||||||
}
|
|
||||||
if (right > mid) {
|
|
||||||
p.setOpacity(st::playerUnavailableOpacity);
|
|
||||||
p.drawPixmap(QRect(mid, top, right - mid, st::playerVolume.pxHeight()), App::sprite(), QRect(st::playerVolume.rect().x() + (mid - left) * cIntRetinaFactor(), st::playerVolume.rect().y(), (right - mid) * cIntRetinaFactor(), st::playerVolume.pxHeight() * cIntRetinaFactor()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_fullAvailable && checkr.intersects(_fullRect)) {
|
|
||||||
float64 o = _stateHovers[OverFull];
|
|
||||||
p.setOpacity(o * 1. + (1. - o) * st::playerInactiveOpacity);
|
|
||||||
p.drawSpriteCenterLeft(_fullRect, width(), st::playerFull);
|
|
||||||
}
|
|
||||||
if (checkr.intersects(_repeatRect)) {
|
|
||||||
float64 o = _stateHovers[OverRepeat];
|
|
||||||
p.setOpacity(_repeat ? 1. : (o * st::playerInactiveOpacity + (1. - o) * st::playerUnavailableOpacity));
|
|
||||||
p.drawSpriteCenterLeft(_repeatRect, width(), st::playerRepeat);
|
|
||||||
}
|
|
||||||
p.setOpacity(1.);
|
|
||||||
|
|
||||||
p.setPen(st::playerTimeFg->p);
|
|
||||||
p.setFont(st::linkFont->f);
|
|
||||||
p.drawTextLeft(_infoRect.x() + _infoRect.width() - _timeWidth, _infoRect.y() + (_infoRect.height() - st::linkFont->height) / 2, width(), _time, _timeWidth);
|
|
||||||
|
|
||||||
textstyleSet(&st::playerNameStyle);
|
|
||||||
p.setPen(st::playerFg->p);
|
|
||||||
_name.drawElided(p, _infoRect.x() + (rtl() ? (_timeWidth + st::playerSkip) : 0), _infoRect.y() + (_infoRect.height() - st::linkFont->height) / 2, _infoRect.width() - _timeWidth - st::playerSkip);
|
|
||||||
textstyleRestore();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_duration) {
|
|
||||||
float64 prg = (_down == OverPlayback) ? _downProgress : a_progress.current();
|
|
||||||
int32 from = _playbackRect.x(), mid = qRound(_playbackRect.x() + prg * _playbackRect.width()), end = _playbackRect.x() + _playbackRect.width();
|
|
||||||
if (mid > from) {
|
|
||||||
p.fillRect(rtl() ? (width() - mid) : from, height() - st::playerLineHeight, mid - from, _playbackRect.height(), st::playerLineActive->b);
|
|
||||||
}
|
|
||||||
if (end > mid) {
|
|
||||||
p.fillRect(rtl() ? (width() - end) : mid, height() - st::playerLineHeight, end - mid, st::playerLineHeight, st::playerLineInactive->b);
|
|
||||||
}
|
|
||||||
if (_stateHovers[OverPlayback] > 0) {
|
|
||||||
p.setOpacity(_stateHovers[OverPlayback]);
|
|
||||||
|
|
||||||
int32 x = mid - (st::playerMoverSize.width() / 2);
|
|
||||||
p.fillRect(rtl() ? (width() - x - st::playerMoverSize.width()) : x, height() - st::playerMoverSize.height(), st::playerMoverSize.width(), st::playerMoverSize.height(), st::playerLineActive->b);
|
|
||||||
}
|
|
||||||
} else if (a_loadProgress.current() > 0) {
|
|
||||||
int32 from = _playbackRect.x(), mid = qRound(_playbackRect.x() + a_loadProgress.current() * _playbackRect.width());
|
|
||||||
if (mid > from) {
|
|
||||||
p.fillRect(rtl() ? (width() - mid) : from, height() - st::playerLineHeight, mid - from, _playbackRect.height(), st::playerLineInactive->b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::mousePressEvent(QMouseEvent *e) {
|
|
||||||
QPoint pos(myrtlpoint(e->pos()));
|
|
||||||
|
|
||||||
if (e->button() == Qt::LeftButton) {
|
|
||||||
_down = OverNone;
|
|
||||||
if (_song && _over == OverPlay) {
|
|
||||||
playPausePressed();
|
|
||||||
return;
|
|
||||||
} else if (_over == OverPrev) {
|
|
||||||
prevPressed();
|
|
||||||
} else if (_over == OverNext) {
|
|
||||||
nextPressed();
|
|
||||||
} else if (_over == OverClose) {
|
|
||||||
_down = OverClose;
|
|
||||||
} else if (_over == OverVolume) {
|
|
||||||
_down = OverVolume;
|
|
||||||
_downCoord = pos.x() - _volumeRect.x();
|
|
||||||
Global::SetSongVolume(snap((_downCoord - ((_volumeRect.width() - st::playerVolume.pxWidth()) / 2)) / float64(st::playerVolume.pxWidth()), 0., 1.));
|
|
||||||
emit audioPlayer()->songVolumeChanged();
|
|
||||||
rtlupdate(_volumeRect);
|
|
||||||
} else if (_over == OverPlayback) {
|
|
||||||
AudioMsgId playing;
|
|
||||||
auto playbackState = audioPlayer()->currentState(&playing, AudioMsgId::Type::Song);
|
|
||||||
if (playing == _song && playbackState.duration) {
|
|
||||||
if (playbackState.state == AudioPlayerPlaying || playbackState.state == AudioPlayerStarting || playbackState.state == AudioPlayerResuming) {
|
|
||||||
audioPlayer()->pauseresume(AudioMsgId::Type::Song);
|
|
||||||
}
|
|
||||||
_down = OverPlayback;
|
|
||||||
_downProgress = snap((pos.x() - _playbackRect.x()) / float64(_playbackRect.width()), 0., 1.);
|
|
||||||
_downDuration = playbackState.duration;
|
|
||||||
_downFrequency = (playbackState.frequency ? playbackState.frequency : AudioVoiceMsgFrequency);
|
|
||||||
|
|
||||||
rtlupdate(_playbackRect);
|
|
||||||
updateDownTime();
|
|
||||||
}
|
|
||||||
} else if (_over == OverFull && _song) {
|
|
||||||
if (HistoryItem *item = App::histItemById(_song.contextId())) {
|
|
||||||
App::main()->showMediaOverview(item->history()->peer, OverviewMusicFiles);
|
|
||||||
}
|
|
||||||
} else if (_over == OverRepeat) {
|
|
||||||
_repeat = !_repeat;
|
|
||||||
updateOverRect(OverRepeat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::updateDownTime() {
|
|
||||||
QString time = formatDurationText(qRound(_downDuration * _downProgress) / _downFrequency);
|
|
||||||
if (time != _time) {
|
|
||||||
_time = time;
|
|
||||||
_timeWidth = st::linkFont->width(_time);
|
|
||||||
rtlupdate(_infoRect);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::updateOverState(OverState newState) {
|
|
||||||
bool result = true;
|
|
||||||
if (_over != newState) {
|
|
||||||
updateOverRect(_over);
|
|
||||||
updateOverRect(newState);
|
|
||||||
if (_over != OverNone) {
|
|
||||||
_stateAnimations.remove(_over);
|
|
||||||
_stateAnimations[-_over] = getms() - ((1. - _stateHovers[_over]) * st::playerDuration);
|
|
||||||
if (!_a_state.animating()) _a_state.start();
|
|
||||||
} else {
|
|
||||||
result = false;
|
|
||||||
}
|
|
||||||
_over = newState;
|
|
||||||
if (newState != OverNone) {
|
|
||||||
_stateAnimations.remove(-_over);
|
|
||||||
_stateAnimations[_over] = getms() - (_stateHovers[_over] * st::playerDuration);
|
|
||||||
if (!_a_state.animating()) _a_state.start();
|
|
||||||
setCursor(style::cur_pointer);
|
|
||||||
} else {
|
|
||||||
setCursor(style::cur_default);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::updateOverRect(OverState state) {
|
|
||||||
switch (state) {
|
|
||||||
case OverPrev: rtlupdate(_prevRect); break;
|
|
||||||
case OverPlay: rtlupdate(_playRect); break;
|
|
||||||
case OverNext: rtlupdate(_nextRect); break;
|
|
||||||
case OverClose: rtlupdate(_closeRect); break;
|
|
||||||
case OverVolume: rtlupdate(_volumeRect); break;
|
|
||||||
case OverFull: rtlupdate(_fullRect); break;
|
|
||||||
case OverRepeat: rtlupdate(_repeatRect); break;
|
|
||||||
case OverPlayback: rtlupdate(_playbackRect); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::updateControls() {
|
|
||||||
_fullAvailable = (_index >= 0);
|
|
||||||
|
|
||||||
History *history = _msgmigrated ? _migrated : _history;
|
|
||||||
_prevAvailable = _fullAvailable && ((_index > 0) || (_index == 0 && _migrated && !_msgmigrated && !_migrated->overview[OverviewMusicFiles].isEmpty()));
|
|
||||||
_nextAvailable = _fullAvailable && ((_index < history->overview[OverviewMusicFiles].size() - 1) || (_msgmigrated && _index == _migrated->overview[OverviewMusicFiles].size() - 1 && _history->overviewLoaded(OverviewMusicFiles) && _history->overviewCount(OverviewMusicFiles) > 0));
|
|
||||||
resizeEvent(0);
|
|
||||||
update();
|
|
||||||
if (_index >= 0 && _index < MediaOverviewStartPerPage) {
|
|
||||||
if (!_history->overviewLoaded(OverviewMusicFiles) || (_migrated && !_migrated->overviewLoaded(OverviewMusicFiles))) {
|
|
||||||
if (App::main()) {
|
|
||||||
if (_msgmigrated || (_migrated && _index == 0 && _history->overviewLoaded(OverviewMusicFiles))) {
|
|
||||||
App::main()->loadMediaBack(_migrated->peer, OverviewMusicFiles);
|
|
||||||
} else {
|
|
||||||
App::main()->loadMediaBack(_history->peer, OverviewMusicFiles);
|
|
||||||
if (_migrated && _index == 0 && _migrated->overview[OverviewMusicFiles].isEmpty() && !_migrated->overviewLoaded(OverviewMusicFiles)) {
|
|
||||||
App::main()->loadMediaBack(_migrated->peer, OverviewMusicFiles);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_msgmigrated && !_history->overviewCountLoaded(OverviewMusicFiles)) {
|
|
||||||
App::main()->preloadOverview(_history->peer, OverviewMusicFiles);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::findCurrent() {
|
|
||||||
_index = -1;
|
|
||||||
if (!_history || !_song.contextId().msg) return;
|
|
||||||
|
|
||||||
const History::MediaOverview *o = &(_msgmigrated ? _migrated : _history)->overview[OverviewMusicFiles];
|
|
||||||
if ((_msgmigrated ? _migrated : _history)->channelId() == _song.contextId().channel) {
|
|
||||||
for (int i = 0, l = o->size(); i < l; ++i) {
|
|
||||||
if (o->at(i) == _song.contextId().msg) {
|
|
||||||
_index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
preloadNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::preloadNext() {
|
|
||||||
if (_index < 0) return;
|
|
||||||
|
|
||||||
History *history = _msgmigrated ? _migrated : _history;
|
|
||||||
const History::MediaOverview *o = &history->overview[OverviewMusicFiles];
|
|
||||||
HistoryItem *next = 0;
|
|
||||||
if (_index < o->size() - 1) {
|
|
||||||
next = App::histItemById(history->channelId(), o->at(_index + 1));
|
|
||||||
} else if (_msgmigrated && _index == o->size() - 1 && _history->overviewLoaded(OverviewMusicFiles) && _history->overviewCount(OverviewMusicFiles) > 0) {
|
|
||||||
next = App::histItemById(_history->channelId(), _history->overview[OverviewMusicFiles].at(0));
|
|
||||||
} else if (_msgmigrated && _index == o->size() - 1 && !_history->overviewCountLoaded(OverviewMusicFiles)) {
|
|
||||||
if (App::main()) App::main()->preloadOverview(_history->peer, OverviewMusicFiles);
|
|
||||||
}
|
|
||||||
if (next) {
|
|
||||||
if (HistoryDocument *document = static_cast<HistoryDocument*>(next->getMedia())) {
|
|
||||||
DocumentData *d = document->getDocument();
|
|
||||||
if (!d->loaded(DocumentData::FilePathResolveSaveFromDataSilent)) {
|
|
||||||
DocumentOpenClickHandler::doOpen(d, ActionOnLoadNone);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::startPlay(const FullMsgId &msgId) {
|
|
||||||
if (HistoryItem *item = App::histItemById(msgId)) {
|
|
||||||
if (HistoryDocument *doc = static_cast<HistoryDocument*>(item->getMedia())) {
|
|
||||||
audioPlayer()->play(AudioMsgId(doc->getDocument(), item->fullId()));
|
|
||||||
updateState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::clearSelection() {
|
|
||||||
for (StateAnimations::const_iterator i = _stateAnimations.cbegin(); i != _stateAnimations.cend(); ++i) {
|
|
||||||
_stateHovers[qAbs(i.key())] = 0;
|
|
||||||
}
|
|
||||||
_stateAnimations.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) {
|
|
||||||
if (_history && (_history->peer == peer || (_migrated && _migrated->peer == peer)) && type == OverviewMusicFiles) {
|
|
||||||
_index = -1;
|
|
||||||
History *history = _msgmigrated ? _migrated : _history;
|
|
||||||
if (history->channelId() == _song.contextId().channel && _song.contextId().msg) {
|
|
||||||
for (int i = 0, l = history->overview[OverviewMusicFiles].size(); i < l; ++i) {
|
|
||||||
if (history->overview[OverviewMusicFiles].at(i) == _song.contextId().msg) {
|
|
||||||
_index = i;
|
|
||||||
preloadNext();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updateControls();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PlayerWidget::seekingSong(const AudioMsgId &song) const {
|
|
||||||
return (_down == OverPlayback) && (song == _song);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::openPlayer() {
|
|
||||||
_playerOpened = true;
|
|
||||||
Shortcuts::enableMediaShortcuts();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PlayerWidget::isOpened() const {
|
|
||||||
return _playerOpened;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::closePlayer() {
|
|
||||||
_playerOpened = false;
|
|
||||||
Shortcuts::disableMediaShortcuts();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::showPlayer() {
|
|
||||||
TWidget::show();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::hidePlayer() {
|
|
||||||
clearSelection();
|
|
||||||
TWidget::hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::step_state(uint64 ms, bool timer) {
|
|
||||||
for (StateAnimations::iterator i = _stateAnimations.begin(); i != _stateAnimations.cend();) {
|
|
||||||
int32 over = qAbs(i.key());
|
|
||||||
updateOverRect(OverState(over));
|
|
||||||
|
|
||||||
float64 dt = float64(ms - i.value()) / st::playerDuration;
|
|
||||||
if (dt >= 1) {
|
|
||||||
_stateHovers[over] = (i.key() > 0) ? 1 : 0;
|
|
||||||
i = _stateAnimations.erase(i);
|
|
||||||
} else {
|
|
||||||
_stateHovers[over] = (i.key() > 0) ? dt : (1 - dt);
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_stateAnimations.isEmpty()) {
|
|
||||||
_a_state.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::mouseMoveEvent(QMouseEvent *e) {
|
|
||||||
_lastMousePos = e->globalPos();
|
|
||||||
updateSelected();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::leaveEvent(QEvent *e) {
|
|
||||||
_lastMousePos = QCursor::pos();
|
|
||||||
updateSelected();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::updateSelected() {
|
|
||||||
QPoint pos(myrtlpoint(mapFromGlobal(_lastMousePos)));
|
|
||||||
|
|
||||||
if (_down == OverVolume) {
|
|
||||||
int32 delta = (pos.x() - _volumeRect.x()) - _downCoord;
|
|
||||||
float64 startFrom = snap((_downCoord - ((_volumeRect.width() - st::playerVolume.pxWidth()) / 2)) / float64(st::playerVolume.pxWidth()), 0., 1.);
|
|
||||||
float64 add = delta / float64(4 * st::playerVolume.pxWidth()), result = snap(startFrom + add, 0., 1.);
|
|
||||||
if (result != Global::SongVolume()) {
|
|
||||||
Global::SetSongVolume(result);
|
|
||||||
emit audioPlayer()->songVolumeChanged();
|
|
||||||
rtlupdate(_volumeRect);
|
|
||||||
}
|
|
||||||
} else if (_down == OverPlayback) {
|
|
||||||
_downProgress = snap((pos.x() - _playbackRect.x()) / float64(_playbackRect.width()), 0., 1.);
|
|
||||||
rtlupdate(_playbackRect);
|
|
||||||
updateDownTime();
|
|
||||||
} else if (_down == OverNone) {
|
|
||||||
bool inInfo = ((pos.x() >= _infoRect.x()) && (pos.x() < _fullRect.x() + _fullRect.width()) && (pos.y() >= _playRect.y()) && (pos.y() <= _playRect.y() + _playRect.height()));
|
|
||||||
if (_prevAvailable && _prevRect.contains(pos)) {
|
|
||||||
updateOverState(OverPrev);
|
|
||||||
} else if (_nextAvailable && _nextRect.contains(pos)) {
|
|
||||||
updateOverState(OverNext);
|
|
||||||
} else if (_playRect.contains(pos)) {
|
|
||||||
updateOverState(OverPlay);
|
|
||||||
} else if (_closeRect.contains(pos)) {
|
|
||||||
updateOverState(OverClose);
|
|
||||||
} else if (_volumeRect.contains(pos)) {
|
|
||||||
updateOverState(OverVolume);
|
|
||||||
} else if (_repeatRect.contains(pos)) {
|
|
||||||
updateOverState(OverRepeat);
|
|
||||||
} else if (_duration && _playbackRect.contains(pos)) {
|
|
||||||
updateOverState(OverPlayback);
|
|
||||||
} else if (_fullAvailable && inInfo) {
|
|
||||||
updateOverState(OverFull);
|
|
||||||
} else if (_over != OverNone) {
|
|
||||||
updateOverState(OverNone);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::mouseReleaseEvent(QMouseEvent *e) {
|
|
||||||
if (_down == OverVolume) {
|
|
||||||
mouseMoveEvent(e);
|
|
||||||
Local::writeUserSettings();
|
|
||||||
} else if (_down == OverPlayback) {
|
|
||||||
mouseMoveEvent(e);
|
|
||||||
AudioMsgId playing;
|
|
||||||
auto playbackState = audioPlayer()->currentState(&playing, AudioMsgId::Type::Song);
|
|
||||||
if (playing == _song && playbackState.duration) {
|
|
||||||
_downDuration = playbackState.duration;
|
|
||||||
audioPlayer()->seek(qRound(_downProgress * _downDuration));
|
|
||||||
|
|
||||||
_showPause = true;
|
|
||||||
|
|
||||||
a_progress = anim::fvalue(_downProgress, _downProgress);
|
|
||||||
_a_progress.stop();
|
|
||||||
}
|
|
||||||
update();
|
|
||||||
} else if (_down == OverClose && _over == OverClose) {
|
|
||||||
closePressed();
|
|
||||||
}
|
|
||||||
_down = OverNone;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::playPressed() {
|
|
||||||
if (!_song || isHidden()) return;
|
|
||||||
|
|
||||||
AudioMsgId playing;
|
|
||||||
auto playbackState = audioPlayer()->currentState(&playing, AudioMsgId::Type::Song);
|
|
||||||
if (playing == _song && !(playbackState.state & AudioPlayerStoppedMask)) {
|
|
||||||
if (playbackState.state == AudioPlayerPausing || playbackState.state == AudioPlayerPaused || playbackState.state == AudioPlayerPausedAtEnd) {
|
|
||||||
audioPlayer()->pauseresume(AudioMsgId::Type::Song);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
audioPlayer()->play(_song);
|
|
||||||
audioPlayer()->notify(_song);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::pausePressed() {
|
|
||||||
if (!_song || isHidden()) return;
|
|
||||||
|
|
||||||
AudioMsgId playing;
|
|
||||||
auto playbackState = audioPlayer()->currentState(&playing, AudioMsgId::Type::Song);
|
|
||||||
if (playing == _song && !(playbackState.state & AudioPlayerStoppedMask)) {
|
|
||||||
if (playbackState.state == AudioPlayerStarting || playbackState.state == AudioPlayerResuming || playbackState.state == AudioPlayerPlaying || playbackState.state == AudioPlayerFinishing) {
|
|
||||||
audioPlayer()->pauseresume(AudioMsgId::Type::Song);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::playPausePressed() {
|
|
||||||
if (!_song || isHidden()) return;
|
|
||||||
|
|
||||||
AudioMsgId playing;
|
|
||||||
auto playbackState = audioPlayer()->currentState(&playing, AudioMsgId::Type::Song);
|
|
||||||
if (playing == _song && !(playbackState.state & AudioPlayerStoppedMask)) {
|
|
||||||
audioPlayer()->pauseresume(AudioMsgId::Type::Song);
|
|
||||||
} else {
|
|
||||||
audioPlayer()->play(_song);
|
|
||||||
audioPlayer()->notify(_song);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::prevPressed() {
|
|
||||||
if (isHidden()) return;
|
|
||||||
|
|
||||||
auto history = _msgmigrated ? _migrated : _history;
|
|
||||||
auto o = history ? &history->overview[OverviewMusicFiles] : nullptr;
|
|
||||||
if (audioPlayer() && o && _index > 0 && _index <= o->size() && !o->isEmpty()) {
|
|
||||||
startPlay(FullMsgId(history->channelId(), o->at(_index - 1)));
|
|
||||||
} else if (!_index && _history && _migrated && !_msgmigrated) {
|
|
||||||
o = &_migrated->overview[OverviewMusicFiles];
|
|
||||||
if (!o->isEmpty()) {
|
|
||||||
startPlay(FullMsgId(_migrated->channelId(), o->at(o->size() - 1)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::nextPressed() {
|
|
||||||
if (isHidden()) return;
|
|
||||||
|
|
||||||
auto history = _msgmigrated ? _migrated : _history;
|
|
||||||
auto o = history ? &history->overview[OverviewMusicFiles] : nullptr;
|
|
||||||
if (audioPlayer() && o && _index >= 0 && _index < o->size() - 1) {
|
|
||||||
startPlay(FullMsgId(history->channelId(), o->at(_index + 1)));
|
|
||||||
} else if (o && (_index == o->size() - 1) && _msgmigrated && _history->overviewLoaded(OverviewMusicFiles)) {
|
|
||||||
o = &_history->overview[OverviewMusicFiles];
|
|
||||||
if (!o->isEmpty()) {
|
|
||||||
startPlay(FullMsgId(_history->channelId(), o->at(0)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::stopPressed() {
|
|
||||||
if (!_song || isHidden()) return;
|
|
||||||
|
|
||||||
audioPlayer()->stop(AudioMsgId::Type::Song);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::closePressed() {
|
|
||||||
stopPressed();
|
|
||||||
if (App::main()) App::main()->closePlayer();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::resizeEvent(QResizeEvent *e) {
|
|
||||||
int32 availh = (height() - st::playerLineHeight);
|
|
||||||
int32 ch = st::playerPlay.pxHeight() + st::playerSkip, ct = (availh - ch) / 2;
|
|
||||||
_playbackRect = QRect(Adaptive::OneColumn() ? 0 : st::lineWidth, height() - st::playerMoverSize.height(), width() - (Adaptive::OneColumn() ? 0 : st::lineWidth), st::playerMoverSize.height());
|
|
||||||
_prevRect = _fullAvailable ? QRect(st::playerSkip / 2, ct, st::playerPrev.pxWidth() + st::playerSkip, ch) : QRect();
|
|
||||||
_playRect = QRect(_fullAvailable ? (_prevRect.x() + _prevRect.width()) : (st::playerSkip / 2), ct, st::playerPlay.pxWidth() + st::playerSkip, ch);
|
|
||||||
_nextRect = _fullAvailable ? QRect(_playRect.x() + _playRect.width(), ct, st::playerNext.pxWidth() + st::playerSkip, ch) : QRect();
|
|
||||||
|
|
||||||
_closeRect = QRect(width() - st::playerSkip / 2 - st::playerClose.pxWidth() - st::playerSkip, ct, st::playerClose.pxWidth() + st::playerSkip, ch);
|
|
||||||
_volumeRect = QRect(_closeRect.x() - st::playerVolume.pxWidth() - st::playerSkip, ct, st::playerVolume.pxWidth() + st::playerSkip, ch);
|
|
||||||
_repeatRect = QRect(_volumeRect.x() - st::playerRepeat.pxWidth() - st::playerSkip, ct, st::playerRepeat.pxWidth() + st::playerSkip, ch);
|
|
||||||
_fullRect = _fullAvailable ? QRect(_repeatRect.x() - st::playerFull.pxWidth() - st::playerSkip, ct, st::playerFull.pxWidth() + st::playerSkip, ch) : QRect();
|
|
||||||
|
|
||||||
int32 infoLeft = (_fullAvailable ? (_nextRect.x() + _nextRect.width()) : (_playRect.x() + _playRect.width()));
|
|
||||||
_infoRect = QRect(infoLeft + st::playerSkip / 2, 0, (_fullAvailable ? _fullRect.x() : _repeatRect.x()) - infoLeft - st::playerSkip, availh);
|
|
||||||
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::step_progress(float64 ms, bool timer) {
|
|
||||||
float64 dt = ms / (2 * AudioVoiceMsgUpdateView);
|
|
||||||
if (_duration && dt >= 1) {
|
|
||||||
_a_progress.stop();
|
|
||||||
a_progress.finish();
|
|
||||||
a_loadProgress.finish();
|
|
||||||
} else {
|
|
||||||
a_progress.update(qMin(dt, 1.), anim::linear);
|
|
||||||
a_loadProgress.update(1. - (st::radialDuration / (st::radialDuration + ms)), anim::linear);
|
|
||||||
}
|
|
||||||
if (timer) rtlupdate(_playbackRect);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::updateState() {
|
|
||||||
updateState(AudioMsgId(), AudioPlaybackState());
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerWidget::updateState(AudioMsgId playing, AudioPlaybackState playbackState) {
|
|
||||||
if (!playing) {
|
|
||||||
playbackState = audioPlayer()->currentState(&playing, AudioMsgId::Type::Song);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool songChanged = false;
|
|
||||||
if (playing && _song != playing) {
|
|
||||||
songChanged = true;
|
|
||||||
_song = playing;
|
|
||||||
if (HistoryItem *item = App::histItemById(_song.contextId())) {
|
|
||||||
_history = item->history();
|
|
||||||
if (_history->peer->migrateFrom()) {
|
|
||||||
_migrated = App::history(_history->peer->migrateFrom()->id);
|
|
||||||
_msgmigrated = false;
|
|
||||||
} else if (_history->peer->migrateTo()) {
|
|
||||||
_migrated = _history;
|
|
||||||
_history = App::history(_migrated->peer->migrateTo()->id);
|
|
||||||
_msgmigrated = true;
|
|
||||||
}
|
|
||||||
findCurrent();
|
|
||||||
} else {
|
|
||||||
_history = nullptr;
|
|
||||||
_msgmigrated = false;
|
|
||||||
_index = -1;
|
|
||||||
}
|
|
||||||
auto song = _song.audio()->song();
|
|
||||||
if (song->performer.isEmpty()) {
|
|
||||||
_name.setText(st::linkFont, song->title.isEmpty() ? (_song.audio()->name.isEmpty() ? qsl("Unknown Track") : _song.audio()->name) : song->title, _textNameOptions);
|
|
||||||
} else {
|
|
||||||
TextCustomTagsMap custom;
|
|
||||||
custom.insert(QChar('c'), qMakePair(textcmdStartLink(1), textcmdStopLink()));
|
|
||||||
_name.setRichText(st::linkFont, QString::fromUtf8("[c]%1[/c] \xe2\x80\x93 %2").arg(textRichPrepare(song->performer)).arg(song->title.isEmpty() ? qsl("Unknown Track") : textRichPrepare(song->title)), _textNameOptions, custom);
|
|
||||||
}
|
|
||||||
updateControls();
|
|
||||||
}
|
|
||||||
|
|
||||||
qint64 position = 0, duration = 0, display = 0;
|
|
||||||
if (playing == _song) {
|
|
||||||
if (!(playbackState.state & AudioPlayerStoppedMask) && playbackState.state != AudioPlayerFinishing) {
|
|
||||||
display = position = playbackState.position;
|
|
||||||
duration = playbackState.duration;
|
|
||||||
} else {
|
|
||||||
display = playbackState.duration;
|
|
||||||
}
|
|
||||||
display = display / (playbackState.frequency ? playbackState.frequency : AudioVoiceMsgFrequency);
|
|
||||||
} else if (_song) {
|
|
||||||
display = _song.audio()->song()->duration;
|
|
||||||
}
|
|
||||||
bool showPause = false, stopped = ((playbackState.state & AudioPlayerStoppedMask) || playbackState.state == AudioPlayerFinishing);
|
|
||||||
bool wasPlaying = (_duration != 0);
|
|
||||||
if (!stopped) {
|
|
||||||
showPause = (playbackState.state == AudioPlayerPlaying || playbackState.state == AudioPlayerResuming || playbackState.state == AudioPlayerStarting);
|
|
||||||
}
|
|
||||||
QString time;
|
|
||||||
float64 progress = 0.;
|
|
||||||
int32 loaded;
|
|
||||||
float64 loadProgress = 1.;
|
|
||||||
if (duration || !_song || !_song.audio() || !_song.audio()->loading()) {
|
|
||||||
time = (_down == OverPlayback) ? _time : formatDurationText(display);
|
|
||||||
progress = duration ? snap(float64(position) / duration, 0., 1.) : 0.;
|
|
||||||
loaded = duration ? _song.audio()->size : 0;
|
|
||||||
} else {
|
|
||||||
loaded = _song.audio()->loading() ? _song.audio()->loadOffset() : 0;
|
|
||||||
time = formatDownloadText(loaded, _song.audio()->size);
|
|
||||||
loadProgress = snap(float64(loaded) / qMax(_song.audio()->size, 1), 0., 1.);
|
|
||||||
}
|
|
||||||
if (time != _time || showPause != _showPause) {
|
|
||||||
if (_time != time) {
|
|
||||||
_time = time;
|
|
||||||
_timeWidth = st::linkFont->width(_time);
|
|
||||||
}
|
|
||||||
_showPause = showPause;
|
|
||||||
if (duration != _duration || position != _position || loaded != _loaded) {
|
|
||||||
if (!songChanged && ((!stopped && duration && _duration) || (!duration && _loaded != loaded))) {
|
|
||||||
a_progress.start(progress);
|
|
||||||
a_loadProgress.start(loadProgress);
|
|
||||||
_a_progress.start();
|
|
||||||
} else {
|
|
||||||
a_progress = anim::fvalue(progress, progress);
|
|
||||||
a_loadProgress = anim::fvalue(loadProgress, loadProgress);
|
|
||||||
_a_progress.stop();
|
|
||||||
}
|
|
||||||
_position = position;
|
|
||||||
_duration = duration;
|
|
||||||
_loaded = loaded;
|
|
||||||
}
|
|
||||||
update();
|
|
||||||
} else if (duration != _duration || position != _position || loaded != _loaded) {
|
|
||||||
if (!songChanged && ((!stopped && duration && _duration) || (!duration && _loaded != loaded))) {
|
|
||||||
a_progress.start(progress);
|
|
||||||
a_loadProgress.start(loadProgress);
|
|
||||||
_a_progress.start();
|
|
||||||
} else {
|
|
||||||
a_progress = anim::fvalue(progress, progress);
|
|
||||||
a_loadProgress = anim::fvalue(loadProgress, loadProgress);
|
|
||||||
_a_progress.stop();
|
|
||||||
}
|
|
||||||
_position = position;
|
|
||||||
_duration = duration;
|
|
||||||
_loaded = loaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wasPlaying && playbackState.state == AudioPlayerStoppedAtEnd) {
|
|
||||||
if (_repeat) {
|
|
||||||
if (_song.audio()) {
|
|
||||||
// audioPlayer()->play(_song);
|
|
||||||
// updateState();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// nextPressed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (songChanged) {
|
|
||||||
emit playerSongChanged(_song.contextId());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,138 +0,0 @@
|
||||||
/*
|
|
||||||
This file is part of Telegram Desktop,
|
|
||||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
|
||||||
|
|
||||||
Telegram Desktop 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 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
It 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.
|
|
||||||
|
|
||||||
In addition, as a special exception, the copyright holders give permission
|
|
||||||
to link the code of portions of this program with the OpenSSL library.
|
|
||||||
|
|
||||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
|
||||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "media/media_audio.h"
|
|
||||||
|
|
||||||
class PlayerWidget : public TWidget {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
PlayerWidget(QWidget *parent);
|
|
||||||
|
|
||||||
void paintEvent(QPaintEvent *e);
|
|
||||||
void mousePressEvent(QMouseEvent *e);
|
|
||||||
void mouseMoveEvent(QMouseEvent *e);
|
|
||||||
void leaveEvent(QEvent *e);
|
|
||||||
void mouseReleaseEvent(QMouseEvent *e);
|
|
||||||
void resizeEvent(QResizeEvent *e);
|
|
||||||
|
|
||||||
void playPressed();
|
|
||||||
void pausePressed();
|
|
||||||
void playPausePressed();
|
|
||||||
void prevPressed();
|
|
||||||
void nextPressed();
|
|
||||||
void stopPressed();
|
|
||||||
void closePressed();
|
|
||||||
|
|
||||||
void step_progress(float64 ms, bool timer);
|
|
||||||
void step_state(uint64 ms, bool timer);
|
|
||||||
|
|
||||||
void updateState(AudioMsgId playing, AudioPlaybackState playbackState);
|
|
||||||
void updateState();
|
|
||||||
void clearSelection();
|
|
||||||
|
|
||||||
void mediaOverviewUpdated(PeerData *peer, MediaOverviewType type);
|
|
||||||
|
|
||||||
bool seekingSong(const AudioMsgId &song) const;
|
|
||||||
|
|
||||||
void openPlayer();
|
|
||||||
bool isOpened() const;
|
|
||||||
void closePlayer();
|
|
||||||
|
|
||||||
void showPlayer();
|
|
||||||
void hidePlayer();
|
|
||||||
|
|
||||||
signals:
|
|
||||||
|
|
||||||
void playerSongChanged(const FullMsgId &msgId);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
// Use startPlayer()/stopPlayer() or showPlayer()/hidePlayer() instead.
|
|
||||||
void show();
|
|
||||||
void hide();
|
|
||||||
|
|
||||||
enum OverState {
|
|
||||||
OverNone = 0,
|
|
||||||
OverPrev,
|
|
||||||
OverPlay,
|
|
||||||
OverNext,
|
|
||||||
OverClose,
|
|
||||||
OverVolume,
|
|
||||||
OverFull,
|
|
||||||
OverRepeat,
|
|
||||||
OverPlayback,
|
|
||||||
|
|
||||||
OverStateCount
|
|
||||||
};
|
|
||||||
void updateDownTime();
|
|
||||||
void updateOverState(OverState newState);
|
|
||||||
void updateOverRect(OverState state);
|
|
||||||
|
|
||||||
void updateControls();
|
|
||||||
void findCurrent();
|
|
||||||
void preloadNext();
|
|
||||||
|
|
||||||
void startPlay(const FullMsgId &msgId);
|
|
||||||
|
|
||||||
QPoint _lastMousePos;
|
|
||||||
void updateSelected();
|
|
||||||
|
|
||||||
bool _playerOpened = false;
|
|
||||||
|
|
||||||
bool _prevAvailable = false;
|
|
||||||
bool _nextAvailable = false;
|
|
||||||
bool _fullAvailable = false;
|
|
||||||
OverState _over = OverNone;
|
|
||||||
OverState _down = OverNone;
|
|
||||||
int32 _downCoord = 0;
|
|
||||||
int64 _downDuration;
|
|
||||||
int32 _downFrequency = AudioVoiceMsgFrequency;
|
|
||||||
float64 _downProgress = 0.;
|
|
||||||
|
|
||||||
float64 _stateHovers[OverStateCount];
|
|
||||||
typedef QMap<int32, uint64> StateAnimations;
|
|
||||||
StateAnimations _stateAnimations;
|
|
||||||
Animation _a_state;
|
|
||||||
|
|
||||||
AudioMsgId _song;
|
|
||||||
bool _msgmigrated = false;
|
|
||||||
int32 _index = -1;
|
|
||||||
History *_migrated = nullptr;
|
|
||||||
History *_history = nullptr;
|
|
||||||
QRect _playRect, _prevRect, _nextRect, _playbackRect;
|
|
||||||
QRect _closeRect, _volumeRect, _fullRect, _repeatRect, _infoRect;
|
|
||||||
int32 _timeWidth = 0;
|
|
||||||
bool _repeat = false;
|
|
||||||
QString _time;
|
|
||||||
Text _name;
|
|
||||||
bool _showPause = false;
|
|
||||||
int64 _position = 0;
|
|
||||||
int64 _duration = 0;
|
|
||||||
int32 _loaded = 0;
|
|
||||||
|
|
||||||
anim::fvalue a_progress = { 0., 0. };
|
|
||||||
anim::fvalue a_loadProgress = { 0., 0. };
|
|
||||||
Animation _a_progress;
|
|
||||||
|
|
||||||
};
|
|
|
@ -38,7 +38,7 @@ Widget::Widget(QWidget *parent, PeerData *peer) : Window::SectionWidget(parent)
|
||||||
_fixedBar->resizeToWidth(width());
|
_fixedBar->resizeToWidth(width());
|
||||||
_fixedBar->show();
|
_fixedBar->show();
|
||||||
|
|
||||||
_fixedBarShadow->setMode(ToggleableShadow::Mode::HiddenFast);
|
_fixedBarShadow->setMode(Ui::ToggleableShadow::Mode::HiddenFast);
|
||||||
_fixedBarShadow->raise();
|
_fixedBarShadow->raise();
|
||||||
updateAdaptiveLayout();
|
updateAdaptiveLayout();
|
||||||
subscribe(Adaptive::Changed(), [this]() { updateAdaptiveLayout(); });
|
subscribe(Adaptive::Changed(), [this]() { updateAdaptiveLayout(); });
|
||||||
|
@ -85,7 +85,7 @@ bool Widget::showInternal(const Window::SectionMemento *memento) {
|
||||||
void Widget::setInternalState(const SectionMemento *memento) {
|
void Widget::setInternalState(const SectionMemento *memento) {
|
||||||
myEnsureResized(this);
|
myEnsureResized(this);
|
||||||
_scroll->scrollToY(memento->_scrollTop);
|
_scroll->scrollToY(memento->_scrollTop);
|
||||||
_fixedBarShadow->setMode(memento->_scrollTop > 0 ? ToggleableShadow::Mode::ShownFast : ToggleableShadow::Mode::HiddenFast);
|
_fixedBarShadow->setMode(memento->_scrollTop > 0 ? Ui::ToggleableShadow::Mode::ShownFast : Ui::ToggleableShadow::Mode::HiddenFast);
|
||||||
}
|
}
|
||||||
|
|
||||||
std_::unique_ptr<Window::SectionMemento> Widget::createMemento() const {
|
std_::unique_ptr<Window::SectionMemento> Widget::createMemento() const {
|
||||||
|
@ -116,14 +116,14 @@ void Widget::resizeEvent(QResizeEvent *e) {
|
||||||
}
|
}
|
||||||
int scrollTop = _scroll->scrollTop();
|
int scrollTop = _scroll->scrollTop();
|
||||||
_inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height());
|
_inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height());
|
||||||
_fixedBarShadow->setMode((scrollTop > 0) ? ToggleableShadow::Mode::Shown : ToggleableShadow::Mode::Hidden);
|
_fixedBarShadow->setMode((scrollTop > 0) ? Ui::ToggleableShadow::Mode::Shown : Ui::ToggleableShadow::Mode::Hidden);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::onScroll() {
|
void Widget::onScroll() {
|
||||||
int scrollTop = _scroll->scrollTop();
|
int scrollTop = _scroll->scrollTop();
|
||||||
_inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height());
|
_inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height());
|
||||||
_fixedBarShadow->setMode((scrollTop > 0) ? ToggleableShadow::Mode::Shown : ToggleableShadow::Mode::Hidden);
|
_fixedBarShadow->setMode((scrollTop > 0) ? Ui::ToggleableShadow::Mode::Shown : Ui::ToggleableShadow::Mode::Hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::showAnimatedHook() {
|
void Widget::showAnimatedHook() {
|
||||||
|
|
|
@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "window/section_widget.h"
|
#include "window/section_widget.h"
|
||||||
|
#include "ui/widgets/shadow.h"
|
||||||
|
|
||||||
class ScrollArea;
|
class ScrollArea;
|
||||||
|
|
||||||
|
@ -70,7 +71,7 @@ private:
|
||||||
ChildWidget<ScrollArea> _scroll;
|
ChildWidget<ScrollArea> _scroll;
|
||||||
ChildWidget<InnerWidget> _inner;
|
ChildWidget<InnerWidget> _inner;
|
||||||
ChildWidget<FixedBar> _fixedBar;
|
ChildWidget<FixedBar> _fixedBar;
|
||||||
ChildWidget<ToggleableShadow> _fixedBarShadow;
|
ChildWidget<Ui::ToggleableShadow> _fixedBarShadow;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "playerwidget.h"
|
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
#include "media/player/media_player_instance.h"
|
#include "media/player/media_player_instance.h"
|
||||||
#include "platform/mac/mac_utilities.h"
|
#include "platform/mac/mac_utilities.h"
|
||||||
|
|
|
@ -24,6 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "settings/settings_inner_widget.h"
|
#include "settings/settings_inner_widget.h"
|
||||||
#include "settings/settings_fixed_bar.h"
|
#include "settings/settings_fixed_bar.h"
|
||||||
#include "styles/style_settings.h"
|
#include "styles/style_settings.h"
|
||||||
|
#include "ui/widgets/shadow.h"
|
||||||
#include "ui/scrollarea.h"
|
#include "ui/scrollarea.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
|
|
|
@ -22,6 +22,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "layerwidget.h"
|
#include "layerwidget.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class PlainShadow;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Settings {
|
namespace Settings {
|
||||||
|
|
||||||
class InnerWidget;
|
class InnerWidget;
|
||||||
|
@ -50,7 +54,7 @@ private:
|
||||||
ChildWidget<ScrollArea> _scroll;
|
ChildWidget<ScrollArea> _scroll;
|
||||||
ChildWidget<InnerWidget> _inner;
|
ChildWidget<InnerWidget> _inner;
|
||||||
ChildWidget<FixedBar> _fixedBar;
|
ChildWidget<FixedBar> _fixedBar;
|
||||||
ChildWidget<PlainShadow> _fixedBarShadow1, _fixedBarShadow2;
|
ChildWidget<Ui::PlainShadow> _fixedBarShadow1, _fixedBarShadow2;
|
||||||
|
|
||||||
int _contentLeft = 0;
|
int _contentLeft = 0;
|
||||||
|
|
||||||
|
|
|
@ -1249,7 +1249,7 @@ void StickerPanInner::selectInlineResult(int row, int column) {
|
||||||
} else if (document->loading()) {
|
} else if (document->loading()) {
|
||||||
document->cancel();
|
document->cancel();
|
||||||
} else {
|
} else {
|
||||||
DocumentOpenClickHandler::doOpen(document, ActionOnLoadNone);
|
DocumentOpenClickHandler::doOpen(document, nullptr, ActionOnLoadNone);
|
||||||
}
|
}
|
||||||
} else if (auto inlineResult = item->getResult()) {
|
} else if (auto inlineResult = item->getResult()) {
|
||||||
if (inlineResult->onChoose(item)) {
|
if (inlineResult->onChoose(item)) {
|
||||||
|
|
|
@ -920,6 +920,11 @@ bool StickerData::setInstalled() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
QString documentSaveFilename(const DocumentData *data, bool forceSavingAs = false, const QString already = QString(), const QDir &dir = QDir()) {
|
QString documentSaveFilename(const DocumentData *data, bool forceSavingAs = false, const QString already = QString(), const QDir &dir = QDir()) {
|
||||||
|
auto alreadySavingFilename = data->loadingFilePath();
|
||||||
|
if (!alreadySavingFilename.isEmpty()) {
|
||||||
|
return alreadySavingFilename;
|
||||||
|
}
|
||||||
|
|
||||||
QString name, filter, caption, prefix;
|
QString name, filter, caption, prefix;
|
||||||
MimeType mimeType = mimeTypeForName(data->mime);
|
MimeType mimeType = mimeTypeForName(data->mime);
|
||||||
QStringList p = mimeType.globPatterns();
|
QStringList p = mimeType.globPatterns();
|
||||||
|
@ -953,19 +958,15 @@ QString documentSaveFilename(const DocumentData *data, bool forceSavingAs = fals
|
||||||
return saveFileName(caption, filter, prefix, name, forceSavingAs, dir);
|
return saveFileName(caption, filter, prefix, name, forceSavingAs, dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DocumentOpenClickHandler::doOpen(DocumentData *data, ActionOnLoad action) {
|
void DocumentOpenClickHandler::doOpen(DocumentData *data, HistoryItem *context, ActionOnLoad action) {
|
||||||
if (!data->date) return;
|
if (!data->date) return;
|
||||||
|
|
||||||
HistoryItem *item = App::hoveredLinkItem() ? App::hoveredLinkItem() : (App::contextItem() ? App::contextItem() : nullptr);
|
auto msgId = context ? context->fullId() : FullMsgId();
|
||||||
FullMsgId msgId;
|
|
||||||
if (item) {
|
|
||||||
msgId = item->fullId();
|
|
||||||
}
|
|
||||||
bool playVoice = data->voice() && audioPlayer();
|
bool playVoice = data->voice() && audioPlayer();
|
||||||
bool playMusic = data->song() && audioPlayer();
|
bool playMusic = data->song() && audioPlayer();
|
||||||
bool playVideo = data->isVideo() && audioPlayer();
|
bool playVideo = data->isVideo() && audioPlayer();
|
||||||
bool playAnimation = data->isAnimation() && item && item->getMedia();
|
bool playAnimation = data->isAnimation();
|
||||||
const FileLocation &location(data->location(true));
|
auto &location = data->location(true);
|
||||||
if (!location.isEmpty() || (!data->data().isEmpty() && (playVoice || playMusic || playVideo || playAnimation))) {
|
if (!location.isEmpty() || (!data->data().isEmpty() && (playVoice || playMusic || playVideo || playAnimation))) {
|
||||||
if (playVoice) {
|
if (playVoice) {
|
||||||
AudioMsgId playing;
|
AudioMsgId playing;
|
||||||
|
@ -992,9 +993,9 @@ void DocumentOpenClickHandler::doOpen(DocumentData *data, ActionOnLoad action) {
|
||||||
}
|
}
|
||||||
} else if (playVideo) {
|
} else if (playVideo) {
|
||||||
if (!data->data().isEmpty()) {
|
if (!data->data().isEmpty()) {
|
||||||
App::wnd()->showDocument(data, item);
|
App::wnd()->showDocument(data, context);
|
||||||
} else if (location.accessEnable()) {
|
} else if (location.accessEnable()) {
|
||||||
App::wnd()->showDocument(data, item);
|
App::wnd()->showDocument(data, context);
|
||||||
location.accessDisable();
|
location.accessDisable();
|
||||||
} else {
|
} else {
|
||||||
auto filepath = location.name();
|
auto filepath = location.name();
|
||||||
|
@ -1013,17 +1014,17 @@ void DocumentOpenClickHandler::doOpen(DocumentData *data, ActionOnLoad action) {
|
||||||
if (App::main()) App::main()->mediaMarkRead(data);
|
if (App::main()) App::main()->mediaMarkRead(data);
|
||||||
} else if (data->size < MediaViewImageSizeLimit) {
|
} else if (data->size < MediaViewImageSizeLimit) {
|
||||||
if (!data->data().isEmpty() && playAnimation) {
|
if (!data->data().isEmpty() && playAnimation) {
|
||||||
if (action == ActionOnLoadPlayInline && item->getMedia()) {
|
if (action == ActionOnLoadPlayInline && context && context->getMedia()) {
|
||||||
item->getMedia()->playInline(item);
|
context->getMedia()->playInline(context);
|
||||||
} else {
|
} else {
|
||||||
App::wnd()->showDocument(data, item);
|
App::wnd()->showDocument(data, context);
|
||||||
}
|
}
|
||||||
} else if (location.accessEnable()) {
|
} else if (location.accessEnable()) {
|
||||||
if (data->isAnimation() || QImageReader(location.name()).canRead()) {
|
if (data->isAnimation() || QImageReader(location.name()).canRead()) {
|
||||||
if (action == ActionOnLoadPlayInline && item && item->getMedia()) {
|
if (action == ActionOnLoadPlayInline && context && context->getMedia()) {
|
||||||
item->getMedia()->playInline(item);
|
context->getMedia()->playInline(context);
|
||||||
} else {
|
} else {
|
||||||
App::wnd()->showDocument(data, item);
|
App::wnd()->showDocument(data, context);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
psOpenFile(location.name());
|
psOpenFile(location.name());
|
||||||
|
@ -1050,11 +1051,13 @@ void DocumentOpenClickHandler::doOpen(DocumentData *data, ActionOnLoad action) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DocumentOpenClickHandler::onClickImpl() const {
|
void DocumentOpenClickHandler::onClickImpl() const {
|
||||||
doOpen(document(), document()->voice() ? ActionOnLoadNone : ActionOnLoadOpen);
|
auto item = App::hoveredLinkItem() ? App::hoveredLinkItem() : (App::contextItem() ? App::contextItem() : nullptr);
|
||||||
|
doOpen(document(), item, document()->voice() ? ActionOnLoadNone : ActionOnLoadOpen);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GifOpenClickHandler::onClickImpl() const {
|
void GifOpenClickHandler::onClickImpl() const {
|
||||||
doOpen(document(), ActionOnLoadPlayInline);
|
auto item = App::hoveredLinkItem() ? App::hoveredLinkItem() : (App::contextItem() ? App::contextItem() : nullptr);
|
||||||
|
doOpen(document(), item, ActionOnLoadPlayInline);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DocumentSaveClickHandler::doSave(DocumentData *data, bool forceSavingAs) {
|
void DocumentSaveClickHandler::doSave(DocumentData *data, bool forceSavingAs) {
|
||||||
|
@ -1355,6 +1358,10 @@ bool DocumentData::loading() const {
|
||||||
return _loader && _loader != CancelledMtpFileLoader;
|
return _loader && _loader != CancelledMtpFileLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString DocumentData::loadingFilePath() const {
|
||||||
|
return loading() ? _loader->fileName() : QString();
|
||||||
|
}
|
||||||
|
|
||||||
bool DocumentData::displayLoading() const {
|
bool DocumentData::displayLoading() const {
|
||||||
return loading() ? (!_loader->loadingLocal() || !_loader->autoLoading()) : uploading();
|
return loading() ? (!_loader->loadingLocal() || !_loader->autoLoading()) : uploading();
|
||||||
}
|
}
|
||||||
|
@ -1378,11 +1385,8 @@ bool DocumentData::uploading() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DocumentData::save(const QString &toFile, ActionOnLoad action, const FullMsgId &actionMsgId, LoadFromCloudSetting fromCloud, bool autoLoading) {
|
void DocumentData::save(const QString &toFile, ActionOnLoad action, const FullMsgId &actionMsgId, LoadFromCloudSetting fromCloud, bool autoLoading) {
|
||||||
_actionOnLoad = action;
|
|
||||||
_actionOnLoadMsgId = actionMsgId;
|
|
||||||
|
|
||||||
if (loaded(FilePathResolveChecked)) {
|
if (loaded(FilePathResolveChecked)) {
|
||||||
const FileLocation &l(location(true));
|
auto &l = location(true);
|
||||||
if (!toFile.isEmpty()) {
|
if (!toFile.isEmpty()) {
|
||||||
if (!_data.isEmpty()) {
|
if (!_data.isEmpty()) {
|
||||||
QFile f(toFile);
|
QFile f(toFile);
|
||||||
|
@ -1393,22 +1397,29 @@ void DocumentData::save(const QString &toFile, ActionOnLoad action, const FullMs
|
||||||
setLocation(FileLocation(StorageFilePartial, toFile));
|
setLocation(FileLocation(StorageFilePartial, toFile));
|
||||||
Local::writeFileLocation(mediaKey(), FileLocation(mtpToStorageType(mtpc_storage_filePartial), toFile));
|
Local::writeFileLocation(mediaKey(), FileLocation(mtpToStorageType(mtpc_storage_filePartial), toFile));
|
||||||
} else if (l.accessEnable()) {
|
} else if (l.accessEnable()) {
|
||||||
QFile(l.name()).copy(toFile);
|
auto alreadyName = l.name();
|
||||||
|
if (alreadyName != toFile) {
|
||||||
|
QFile(alreadyName).copy(toFile);
|
||||||
|
}
|
||||||
l.accessDisable();
|
l.accessDisable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_actionOnLoad = action;
|
||||||
|
_actionOnLoadMsgId = actionMsgId;
|
||||||
performActionOnLoad();
|
performActionOnLoad();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_loader == CancelledMtpFileLoader) _loader = 0;
|
if (_loader == CancelledMtpFileLoader) _loader = nullptr;
|
||||||
if (_loader) {
|
if (_loader) {
|
||||||
if (!_loader->setFileName(toFile)) {
|
if (!_loader->setFileName(toFile)) {
|
||||||
cancel();
|
cancel(); // changes _actionOnLoad
|
||||||
_loader = 0;
|
_loader = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_actionOnLoad = action;
|
||||||
|
_actionOnLoadMsgId = actionMsgId;
|
||||||
if (_loader) {
|
if (_loader) {
|
||||||
if (fromCloud == LoadFromCloudOrLocal) _loader->permitLoadFromCloud();
|
if (fromCloud == LoadFromCloudOrLocal) _loader->permitLoadFromCloud();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1083,6 +1083,7 @@ public:
|
||||||
};
|
};
|
||||||
bool loaded(FilePathResolveType type = FilePathResolveCached) const;
|
bool loaded(FilePathResolveType type = FilePathResolveCached) const;
|
||||||
bool loading() const;
|
bool loading() const;
|
||||||
|
QString loadingFilePath() const;
|
||||||
bool displayLoading() const;
|
bool displayLoading() const;
|
||||||
void save(const QString &toFile, ActionOnLoad action = ActionOnLoadNone, const FullMsgId &actionMsgId = FullMsgId(), LoadFromCloudSetting fromCloud = LoadFromCloudOrLocal, bool autoLoading = false);
|
void save(const QString &toFile, ActionOnLoad action = ActionOnLoadNone, const FullMsgId &actionMsgId = FullMsgId(), LoadFromCloudSetting fromCloud = LoadFromCloudOrLocal, bool autoLoading = false);
|
||||||
void cancel();
|
void cancel();
|
||||||
|
@ -1320,7 +1321,7 @@ protected:
|
||||||
class DocumentOpenClickHandler : public DocumentClickHandler {
|
class DocumentOpenClickHandler : public DocumentClickHandler {
|
||||||
public:
|
public:
|
||||||
using DocumentClickHandler::DocumentClickHandler;
|
using DocumentClickHandler::DocumentClickHandler;
|
||||||
static void doOpen(DocumentData *document, ActionOnLoad action = ActionOnLoadOpen);
|
static void doOpen(DocumentData *document, HistoryItem *context, ActionOnLoad action = ActionOnLoadOpen);
|
||||||
protected:
|
protected:
|
||||||
void onClickImpl() const override;
|
void onClickImpl() const override;
|
||||||
};
|
};
|
||||||
|
|
|
@ -29,7 +29,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "boxes/aboutbox.h"
|
#include "boxes/aboutbox.h"
|
||||||
#include "media/media_audio.h"
|
#include "media/media_audio.h"
|
||||||
#include "media/player/media_player_title_button.h"
|
#include "media/player/media_player_title_button.h"
|
||||||
#include "media/player/media_player_widget.h"
|
#include "media/player/media_player_panel.h"
|
||||||
#include "media/player/media_player_instance.h"
|
#include "media/player/media_player_instance.h"
|
||||||
|
|
||||||
class TitleWidget::Hider : public TWidget {
|
class TitleWidget::Hider : public TWidget {
|
||||||
|
@ -103,10 +103,16 @@ TitleWidget::TitleWidget(QWidget *parent) : TWidget(parent)
|
||||||
|
|
||||||
subscribe(Adaptive::Changed(), [this]() { updateAdaptiveLayout(); });
|
subscribe(Adaptive::Changed(), [this]() { updateAdaptiveLayout(); });
|
||||||
if (Media::Player::exists()) {
|
if (Media::Player::exists()) {
|
||||||
subscribe(Media::Player::instance()->createdNotifier(), [this](const Media::Player::CreatedEvent &e) {
|
subscribe(Media::Player::instance()->createdNotifier(), [this](const Media::Player::PanelEvent &e) {
|
||||||
if (!_player) {
|
if (!_player) {
|
||||||
_player.create(this);
|
_player.create(this);
|
||||||
_player->installEventFilter(e.widget);
|
updateControlsVisibility();
|
||||||
|
}
|
||||||
|
_player->installEventFilter(e.panel);
|
||||||
|
});
|
||||||
|
subscribe(Media::Player::instance()->destroyedNotifier(), [this](const Media::Player::PanelEvent &e) {
|
||||||
|
if (_player) {
|
||||||
|
_player.destroyDelayed();
|
||||||
updateControlsVisibility();
|
updateControlsVisibility();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -27,7 +27,7 @@ class MainWindow;
|
||||||
namespace Media {
|
namespace Media {
|
||||||
namespace Player {
|
namespace Player {
|
||||||
class TitleButton;
|
class TitleButton;
|
||||||
class CreatedEvent;
|
class PanelEvent;
|
||||||
} // namespace Player
|
} // namespace Player
|
||||||
} // namespace Media
|
} // namespace Media
|
||||||
class AudioMsgId;
|
class AudioMsgId;
|
||||||
|
@ -71,8 +71,6 @@ private:
|
||||||
void updateSystemButtonsVisibility();
|
void updateSystemButtonsVisibility();
|
||||||
void updateControlsPosition();
|
void updateControlsPosition();
|
||||||
|
|
||||||
void handleMediaPlayerCreated(const Media::Player::CreatedEvent &e);
|
|
||||||
|
|
||||||
style::color statusColor;
|
style::color statusColor;
|
||||||
|
|
||||||
class Hider;
|
class Hider;
|
||||||
|
|
|
@ -84,9 +84,9 @@ void RectShadow::paint(Painter &p, const QRect &box, int shifty, Sides sides) {
|
||||||
|
|
||||||
bool wasSmooth = p.renderHints().testFlag(QPainter::SmoothPixmapTransform);
|
bool wasSmooth = p.renderHints().testFlag(QPainter::SmoothPixmapTransform);
|
||||||
if (wasSmooth) p.setRenderHint(QPainter::SmoothPixmapTransform, false);
|
if (wasSmooth) p.setRenderHint(QPainter::SmoothPixmapTransform, false);
|
||||||
if (left) p.drawPixmap(box.left() - countsize + shifty, box.top() + (top ? minus : 0) + shifty, countsize - shifty, box.height() - (bottom ? minus : 0) - (top ? minus : 0), _left, 0, 0, count - rshifty, 1);
|
if (left) p.drawPixmap(box.left() - countsize + shifty, box.top() + (top ? (minus + shifty) : 0), countsize - shifty, box.height() - (bottom ? (minus - shifty) : 0) - (top ? (minus + shifty) : 0), _left, 0, 0, count - rshifty, 1);
|
||||||
if (top) p.drawPixmap(box.left() + (left ? minus : 0), box.top() - countsize + 2 * shifty, box.width() - (right ? minus : 0) - (left ? minus : 0), countsize - 2 * shifty, _top, 0, 0, 1, count - 2 * rshifty);
|
if (top) p.drawPixmap(box.left() + (left ? minus : 0), box.top() - countsize + 2 * shifty, box.width() - (right ? minus : 0) - (left ? minus : 0), countsize - 2 * shifty, _top, 0, 0, 1, count - 2 * rshifty);
|
||||||
if (right) p.drawPixmap(box.left() + box.width(), box.top() + (top ? minus : 0) + shifty, countsize - shifty, box.height() - (bottom ? minus : 0) - (top ? minus : 0), _right, rshifty, 0, count - rshifty, 1);
|
if (right) p.drawPixmap(box.left() + box.width(), box.top() + (top ? (minus + shifty) : 0), countsize - shifty, box.height() - (bottom ? (minus - shifty) : 0) - (top ? (minus + shifty) : 0), _right, rshifty, 0, count - rshifty, 1);
|
||||||
if (bottom) p.drawPixmap(box.left() + (left ? minus : 0), box.top() + box.height(), box.width() - (right ? minus : 0) - (left ? minus : 0), countsize, _bottom, 0, 0, 1, count);
|
if (bottom) p.drawPixmap(box.left() + (left ? minus : 0), box.top() + box.height(), box.width() - (right ? minus : 0) - (left ? minus : 0), countsize, _bottom, 0, 0, 1, count);
|
||||||
if (wasSmooth) p.setRenderHint(QPainter::SmoothPixmapTransform);
|
if (wasSmooth) p.setRenderHint(QPainter::SmoothPixmapTransform);
|
||||||
}
|
}
|
||||||
|
|
|
@ -282,13 +282,13 @@ using QueryList = QList<Query>;
|
||||||
NeverFreedPointer<QueryList> Queries;
|
NeverFreedPointer<QueryList> Queries;
|
||||||
|
|
||||||
void StartCallback() {
|
void StartCallback() {
|
||||||
Queries.makeIfNull();
|
Queries.createIfNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
QueryId queryReadFile(const QString &caption, const QString &filter) {
|
QueryId queryReadFile(const QString &caption, const QString &filter) {
|
||||||
Queries.makeIfNull();
|
Queries.createIfNull();
|
||||||
|
|
||||||
Queries->push_back(Query(Query::Type::ReadFile, caption, filter));
|
Queries->push_back(Query(Query::Type::ReadFile, caption, filter));
|
||||||
Global::RefHandleFileDialogQueue().call();
|
Global::RefHandleFileDialogQueue().call();
|
||||||
|
@ -296,7 +296,7 @@ QueryId queryReadFile(const QString &caption, const QString &filter) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QueryId queryReadFiles(const QString &caption, const QString &filter) {
|
QueryId queryReadFiles(const QString &caption, const QString &filter) {
|
||||||
Queries.makeIfNull();
|
Queries.createIfNull();
|
||||||
|
|
||||||
Queries->push_back(Query(Query::Type::ReadFiles, caption, filter));
|
Queries->push_back(Query(Query::Type::ReadFiles, caption, filter));
|
||||||
Global::RefHandleFileDialogQueue().call();
|
Global::RefHandleFileDialogQueue().call();
|
||||||
|
@ -304,7 +304,7 @@ QueryId queryReadFiles(const QString &caption, const QString &filter) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QueryId queryWriteFile(const QString &caption, const QString &filter, const QString &filePath) {
|
QueryId queryWriteFile(const QString &caption, const QString &filter, const QString &filePath) {
|
||||||
Queries.makeIfNull();
|
Queries.createIfNull();
|
||||||
|
|
||||||
Queries->push_back(Query(Query::Type::WriteFile, caption, filter, filePath));
|
Queries->push_back(Query(Query::Type::WriteFile, caption, filter, filePath));
|
||||||
Global::RefHandleFileDialogQueue().call();
|
Global::RefHandleFileDialogQueue().call();
|
||||||
|
@ -312,7 +312,7 @@ QueryId queryWriteFile(const QString &caption, const QString &filter, const QStr
|
||||||
}
|
}
|
||||||
|
|
||||||
QueryId queryReadFolder(const QString &caption) {
|
QueryId queryReadFolder(const QString &caption) {
|
||||||
Queries.makeIfNull();
|
Queries.createIfNull();
|
||||||
|
|
||||||
Queries->push_back(Query(Query::Type::ReadFolder, caption));
|
Queries->push_back(Query(Query::Type::ReadFolder, caption));
|
||||||
Global::RefHandleFileDialogQueue().call();
|
Global::RefHandleFileDialogQueue().call();
|
||||||
|
|
|
@ -46,7 +46,7 @@ void stopModules() {
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void registerModule(ModuleBase *module) {
|
void registerModule(ModuleBase *module) {
|
||||||
styleModules.makeIfNull();
|
styleModules.createIfNull();
|
||||||
styleModules->push_back(module);
|
styleModules->push_back(module);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -159,7 +159,7 @@ void MonoIcon::ensureLoaded() const {
|
||||||
if (_owningPixmap) {
|
if (_owningPixmap) {
|
||||||
_pixmap = createIconPixmap(_mask, _color);
|
_pixmap = createIconPixmap(_mask, _color);
|
||||||
} else {
|
} else {
|
||||||
iconPixmaps.makeIfNull();
|
iconPixmaps.createIfNull();
|
||||||
auto key = qMakePair(_mask, colorKey(_color->c));
|
auto key = qMakePair(_mask, colorKey(_color->c));
|
||||||
auto i = iconPixmaps->constFind(key);
|
auto i = iconPixmaps->constFind(key);
|
||||||
if (i == iconPixmaps->cend()) {
|
if (i == iconPixmaps->cend()) {
|
||||||
|
|
|
@ -40,7 +40,7 @@ Manager::Manager(QWidget *parent) : QObject(parent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager *Manager::instance(QWidget *parent) {
|
Manager *Manager::instance(QWidget *parent) {
|
||||||
_managers.makeIfNull();
|
_managers.createIfNull();
|
||||||
auto i = _managers->constFind(parent);
|
auto i = _managers->constFind(parent);
|
||||||
if (i == _managers->cend()) {
|
if (i == _managers->cend()) {
|
||||||
i = _managers->insert(parent, new Manager(parent));
|
i = _managers->insert(parent, new Manager(parent));
|
||||||
|
|
|
@ -78,42 +78,6 @@ QPixmap myGrab(TWidget *target, QRect rect) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Mode {
|
|
||||||
Shown,
|
|
||||||
ShownFast,
|
|
||||||
Hidden,
|
|
||||||
HiddenFast
|
|
||||||
};
|
|
||||||
void ToggleableShadow::setMode(Mode mode) {
|
|
||||||
if (mode == Mode::ShownFast || mode == Mode::HiddenFast) {
|
|
||||||
if (!_a_opacity.animating()) {
|
|
||||||
_a_opacity.finish();
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_shown && (mode == Mode::Hidden || mode == Mode::HiddenFast)) {
|
|
||||||
_shown = false;
|
|
||||||
if (mode == Mode::Hidden) {
|
|
||||||
_a_opacity.start([this] { update(); }, 1., 0., st::shadowToggleDuration);
|
|
||||||
}
|
|
||||||
} else if (!_shown && (mode == Mode::Shown || mode == Mode::ShownFast)) {
|
|
||||||
_shown = true;
|
|
||||||
if (mode == Mode::Shown) {
|
|
||||||
_a_opacity.start([this] { update(); }, 0., 1., st::shadowToggleDuration);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ToggleableShadow::paintEvent(QPaintEvent *e) {
|
|
||||||
Painter p(this);
|
|
||||||
if (_a_opacity.animating(getms())) {
|
|
||||||
p.setOpacity(_a_opacity.current());
|
|
||||||
} else if (!_shown) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
p.fillRect(e->rect(), _color);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sendSynteticMouseEvent(QWidget *widget, QEvent::Type type, Qt::MouseButton button, const QPoint &globalPoint) {
|
void sendSynteticMouseEvent(QWidget *widget, QEvent::Type type, Qt::MouseButton button, const QPoint &globalPoint) {
|
||||||
if (auto windowHandle = widget->window()->windowHandle()) {
|
if (auto windowHandle = widget->window()->windowHandle()) {
|
||||||
auto localPoint = windowHandle->mapFromGlobal(globalPoint);
|
auto localPoint = windowHandle->mapFromGlobal(globalPoint);
|
||||||
|
|
|
@ -120,52 +120,59 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#define T_WIDGET public: \
|
#define T_WIDGET \
|
||||||
TWidget *tparent() { \
|
public: \
|
||||||
return qobject_cast<TWidget*>(parentWidget()); \
|
TWidget *tparent() { \
|
||||||
} \
|
return qobject_cast<TWidget*>(parentWidget()); \
|
||||||
const TWidget *tparent() const { \
|
} \
|
||||||
return qobject_cast<const TWidget*>(parentWidget()); \
|
const TWidget *tparent() const { \
|
||||||
} \
|
return qobject_cast<const TWidget*>(parentWidget()); \
|
||||||
virtual void leaveToChildEvent(QEvent *e, QWidget *child) { /* e -- from enterEvent() of child TWidget */ \
|
} \
|
||||||
} \
|
virtual void leaveToChildEvent(QEvent *e, QWidget *child) { /* e -- from enterEvent() of child TWidget */ \
|
||||||
virtual void enterFromChildEvent(QEvent *e, QWidget *child) { /* e -- from leaveEvent() of child TWidget */ \
|
} \
|
||||||
} \
|
virtual void enterFromChildEvent(QEvent *e, QWidget *child) { /* e -- from leaveEvent() of child TWidget */ \
|
||||||
void moveToLeft(int x, int y, int outerw = 0) { \
|
} \
|
||||||
move(rtl() ? ((outerw > 0 ? outerw : parentWidget()->width()) - x - width()) : x, y); \
|
void moveToLeft(int x, int y, int outerw = 0) { \
|
||||||
} \
|
move(rtl() ? ((outerw > 0 ? outerw : parentWidget()->width()) - x - width()) : x, y); \
|
||||||
void moveToRight(int x, int y, int outerw = 0) { \
|
} \
|
||||||
move(rtl() ? x : ((outerw > 0 ? outerw : parentWidget()->width()) - x - width()), y); \
|
void moveToRight(int x, int y, int outerw = 0) { \
|
||||||
} \
|
move(rtl() ? x : ((outerw > 0 ? outerw : parentWidget()->width()) - x - width()), y); \
|
||||||
QPoint myrtlpoint(int x, int y) const { \
|
} \
|
||||||
return rtlpoint(x, y, width()); \
|
void setGeometryToLeft(int x, int y, int w, int h, int outerw = 0) { \
|
||||||
} \
|
setGeometry(rtl() ? ((outerw > 0 ? outerw : parentWidget()->width()) - x - w) : x, y, w, h); \
|
||||||
QPoint myrtlpoint(const QPoint p) const { \
|
} \
|
||||||
return rtlpoint(p, width()); \
|
void setGeometryToRight(int x, int y, int w, int h, int outerw = 0) { \
|
||||||
} \
|
setGeometry(rtl() ? x : ((outerw > 0 ? outerw : parentWidget()->width()) - x - w), y, w, h); \
|
||||||
QRect myrtlrect(int x, int y, int w, int h) const { \
|
} \
|
||||||
return rtlrect(x, y, w, h, width()); \
|
QPoint myrtlpoint(int x, int y) const { \
|
||||||
} \
|
return rtlpoint(x, y, width()); \
|
||||||
QRect myrtlrect(const QRect &r) { \
|
} \
|
||||||
return rtlrect(r, width()); \
|
QPoint myrtlpoint(const QPoint p) const { \
|
||||||
} \
|
return rtlpoint(p, width()); \
|
||||||
void rtlupdate(const QRect &r) { \
|
} \
|
||||||
update(myrtlrect(r)); \
|
QRect myrtlrect(int x, int y, int w, int h) const { \
|
||||||
} \
|
return rtlrect(x, y, w, h, width()); \
|
||||||
void rtlupdate(int x, int y, int w, int h) { \
|
} \
|
||||||
update(myrtlrect(x, y, w, h)); \
|
QRect myrtlrect(const QRect &r) const { \
|
||||||
} \
|
return rtlrect(r, width()); \
|
||||||
|
} \
|
||||||
|
void rtlupdate(const QRect &r) { \
|
||||||
|
update(myrtlrect(r)); \
|
||||||
|
} \
|
||||||
|
void rtlupdate(int x, int y, int w, int h) { \
|
||||||
|
update(myrtlrect(x, y, w, h)); \
|
||||||
|
} \
|
||||||
protected: \
|
protected: \
|
||||||
void enterEvent(QEvent *e) override { \
|
void enterEvent(QEvent *e) override { \
|
||||||
TWidget *p(tparent()); \
|
TWidget *p(tparent()); \
|
||||||
if (p) p->leaveToChildEvent(e, this); \
|
if (p) p->leaveToChildEvent(e, this); \
|
||||||
return enterEventHook(e); \
|
return enterEventHook(e); \
|
||||||
} \
|
} \
|
||||||
void leaveEvent(QEvent *e) override { \
|
void leaveEvent(QEvent *e) override { \
|
||||||
TWidget *p(tparent()); \
|
TWidget *p(tparent()); \
|
||||||
if (p) p->enterFromChildEvent(e, this); \
|
if (p) p->enterFromChildEvent(e, this); \
|
||||||
return leaveEventHook(e); \
|
return leaveEventHook(e); \
|
||||||
}
|
}
|
||||||
|
|
||||||
class TWidget : public QWidget {
|
class TWidget : public QWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -239,48 +246,6 @@ protected:
|
||||||
void myEnsureResized(QWidget *target);
|
void myEnsureResized(QWidget *target);
|
||||||
QPixmap myGrab(TWidget *target, QRect rect = QRect());
|
QPixmap myGrab(TWidget *target, QRect rect = QRect());
|
||||||
|
|
||||||
class PlainShadow : public TWidget {
|
|
||||||
public:
|
|
||||||
PlainShadow(QWidget *parent, const style::color &color) : TWidget(parent), _color(color) {
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void paintEvent(QPaintEvent *e) override {
|
|
||||||
Painter(this).fillRect(e->rect(), _color->b);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const style::color &_color;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class ToggleableShadow : public TWidget {
|
|
||||||
public:
|
|
||||||
ToggleableShadow(QWidget *parent, const style::color &color) : TWidget(parent), _color(color) {
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class Mode {
|
|
||||||
Shown,
|
|
||||||
ShownFast,
|
|
||||||
Hidden,
|
|
||||||
HiddenFast
|
|
||||||
};
|
|
||||||
void setMode(Mode mode);
|
|
||||||
|
|
||||||
bool isFullyShown() const {
|
|
||||||
return _shown && !_a_opacity.animating();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void paintEvent(QPaintEvent *e) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
const style::color &_color;
|
|
||||||
FloatAnimation _a_opacity;
|
|
||||||
bool _shown = true;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class SingleDelayedCall : public QObject {
|
class SingleDelayedCall : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,129 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop 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 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It 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.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "ui/widgets/continuous_slider.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
ContinuousSlider::ContinuousSlider(QWidget *parent) : TWidget(parent)
|
||||||
|
, _a_value(animation(this, &ContinuousSlider::step_value)) {
|
||||||
|
setCursor(style::cur_pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
float64 ContinuousSlider::value() const {
|
||||||
|
return a_value.current();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContinuousSlider::setDisabled(bool disabled) {
|
||||||
|
if (_disabled != disabled) {
|
||||||
|
_disabled = disabled;
|
||||||
|
setCursor(_disabled ? style::cur_default : style::cur_pointer);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContinuousSlider::setValue(float64 value, bool animated) {
|
||||||
|
if (animated) {
|
||||||
|
a_value.start(value);
|
||||||
|
_a_value.start();
|
||||||
|
} else {
|
||||||
|
a_value = anim::fvalue(value, value);
|
||||||
|
_a_value.stop();
|
||||||
|
}
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContinuousSlider::setFadeOpacity(float64 opacity) {
|
||||||
|
_fadeOpacity = opacity;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContinuousSlider::step_value(float64 ms, bool timer) {
|
||||||
|
float64 dt = ms / (2 * AudioVoiceMsgUpdateView);
|
||||||
|
if (dt >= 1) {
|
||||||
|
_a_value.stop();
|
||||||
|
a_value.finish();
|
||||||
|
} else {
|
||||||
|
a_value.update(qMin(dt, 1.), anim::linear);
|
||||||
|
}
|
||||||
|
if (timer) update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContinuousSlider::mouseMoveEvent(QMouseEvent *e) {
|
||||||
|
if (_mouseDown) {
|
||||||
|
updateDownValueFromPos(e->pos());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float64 ContinuousSlider::computeValue(const QPoint &pos) const {
|
||||||
|
auto seekRect = myrtlrect(getSeekRect());
|
||||||
|
auto result = isHorizontal() ?
|
||||||
|
(pos.x() - seekRect.x()) / float64(seekRect.width()) :
|
||||||
|
(1. - (pos.y() - seekRect.y()) / float64(seekRect.height()));
|
||||||
|
return snap(result, 0., 1.);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContinuousSlider::mousePressEvent(QMouseEvent *e) {
|
||||||
|
_mouseDown = true;
|
||||||
|
_downValue = computeValue(e->pos());
|
||||||
|
update();
|
||||||
|
if (_changeProgressCallback) {
|
||||||
|
_changeProgressCallback(_downValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContinuousSlider::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
|
if (_mouseDown) {
|
||||||
|
_mouseDown = false;
|
||||||
|
if (_changeFinishedCallback) {
|
||||||
|
_changeFinishedCallback(_downValue);
|
||||||
|
}
|
||||||
|
a_value = anim::fvalue(_downValue, _downValue);
|
||||||
|
_a_value.stop();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContinuousSlider::updateDownValueFromPos(const QPoint &pos) {
|
||||||
|
_downValue = computeValue(pos);
|
||||||
|
update();
|
||||||
|
if (_changeProgressCallback) {
|
||||||
|
_changeProgressCallback(_downValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContinuousSlider::enterEvent(QEvent *e) {
|
||||||
|
setOver(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContinuousSlider::leaveEvent(QEvent *e) {
|
||||||
|
setOver(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContinuousSlider::setOver(bool over) {
|
||||||
|
if (_over == over) return;
|
||||||
|
|
||||||
|
_over = over;
|
||||||
|
auto from = _over ? 0. : 1., to = _over ? 1. : 0.;
|
||||||
|
_a_over.start([this] { update(); }, from, to, getOverDuration());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Ui
|
|
@ -0,0 +1,109 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop 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 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It 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.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
class ContinuousSlider : public TWidget {
|
||||||
|
public:
|
||||||
|
ContinuousSlider(QWidget *parent);
|
||||||
|
|
||||||
|
enum class Direction {
|
||||||
|
Horizontal,
|
||||||
|
Vertical,
|
||||||
|
};
|
||||||
|
void setDirection(Direction direction) {
|
||||||
|
_direction = direction;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
float64 value() const;
|
||||||
|
void setValue(float64 value, bool animated);
|
||||||
|
void setFadeOpacity(float64 opacity);
|
||||||
|
void setDisabled(bool disabled);
|
||||||
|
|
||||||
|
using Callback = base::lambda_unique<void(float64)>;
|
||||||
|
void setChangeProgressCallback(Callback &&callback) {
|
||||||
|
_changeProgressCallback = std_::move(callback);
|
||||||
|
}
|
||||||
|
void setChangeFinishedCallback(Callback &&callback) {
|
||||||
|
_changeFinishedCallback = std_::move(callback);
|
||||||
|
}
|
||||||
|
bool isChanging() const {
|
||||||
|
return _mouseDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void mouseMoveEvent(QMouseEvent *e) override;
|
||||||
|
void mousePressEvent(QMouseEvent *e) override;
|
||||||
|
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||||
|
void enterEvent(QEvent *e) override;
|
||||||
|
void leaveEvent(QEvent *e) override;
|
||||||
|
|
||||||
|
float64 fadeOpacity() const {
|
||||||
|
return _fadeOpacity;
|
||||||
|
}
|
||||||
|
float64 getCurrentValue(uint64 ms) {
|
||||||
|
_a_value.step(ms);
|
||||||
|
return _mouseDown ? _downValue : a_value.current();
|
||||||
|
}
|
||||||
|
float64 getCurrentOverFactor(uint64 ms) {
|
||||||
|
return _a_over.current(ms, _over ? 1. : 0.);
|
||||||
|
}
|
||||||
|
bool isDisabled() const {
|
||||||
|
return _disabled;
|
||||||
|
}
|
||||||
|
Direction getDirection() const {
|
||||||
|
return _direction;
|
||||||
|
}
|
||||||
|
bool isHorizontal() const {
|
||||||
|
return (_direction == Direction::Horizontal);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual QRect getSeekRect() const = 0;
|
||||||
|
virtual float64 getOverDuration() const = 0;
|
||||||
|
|
||||||
|
void step_value(float64 ms, bool timer);
|
||||||
|
void setOver(bool over);
|
||||||
|
float64 computeValue(const QPoint &pos) const;
|
||||||
|
void updateDownValueFromPos(const QPoint &pos);
|
||||||
|
|
||||||
|
Direction _direction = Direction::Horizontal;
|
||||||
|
bool _disabled = false;
|
||||||
|
|
||||||
|
Callback _changeProgressCallback;
|
||||||
|
Callback _changeFinishedCallback;
|
||||||
|
|
||||||
|
bool _over = false;
|
||||||
|
FloatAnimation _a_over;
|
||||||
|
|
||||||
|
anim::fvalue a_value = { 0., 0. };
|
||||||
|
Animation _a_value;
|
||||||
|
|
||||||
|
bool _mouseDown = false;
|
||||||
|
float64 _downValue = 0.;
|
||||||
|
|
||||||
|
float64 _fadeOpacity = 1.;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Ui
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop 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 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It 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.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "ui/widgets/filled_slider.h"
|
||||||
|
|
||||||
|
#include "styles/style_widgets.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
FilledSlider::FilledSlider(QWidget *parent, const style::FilledSlider &st) : ContinuousSlider(parent)
|
||||||
|
, _st(st) {
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect FilledSlider::getSeekRect() const {
|
||||||
|
return QRect(0, 0, width(), height());
|
||||||
|
}
|
||||||
|
|
||||||
|
float64 FilledSlider::getOverDuration() const {
|
||||||
|
return _st.duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilledSlider::paintEvent(QPaintEvent *e) {
|
||||||
|
Painter p(this);
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.setRenderHint(QPainter::HighQualityAntialiasing);
|
||||||
|
|
||||||
|
auto masterOpacity = fadeOpacity();
|
||||||
|
auto ms = getms();
|
||||||
|
auto disabled = isDisabled();
|
||||||
|
auto over = getCurrentOverFactor(ms);
|
||||||
|
auto lineWidth = _st.lineWidth + ((_st.fullWidth - _st.lineWidth) * over);
|
||||||
|
auto lineWidthRounded = qFloor(lineWidth);
|
||||||
|
auto lineWidthPartial = lineWidth - lineWidthRounded;
|
||||||
|
auto seekRect = getSeekRect();
|
||||||
|
auto value = getCurrentValue(ms);
|
||||||
|
auto from = seekRect.x(), mid = disabled ? from : qRound(from + value * seekRect.width()), end = from + seekRect.width();
|
||||||
|
if (mid > from) {
|
||||||
|
p.setOpacity(masterOpacity);
|
||||||
|
p.fillRect(from, height() - lineWidthRounded, (mid - from), lineWidthRounded, _st.activeFg);
|
||||||
|
if (lineWidthPartial > 0.01) {
|
||||||
|
p.setOpacity(masterOpacity * lineWidthPartial);
|
||||||
|
p.fillRect(from, height() - lineWidthRounded - 1, (mid - from), 1, _st.activeFg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (end > mid && over > 0) {
|
||||||
|
p.setOpacity(masterOpacity * over);
|
||||||
|
p.fillRect(mid, height() - lineWidthRounded, (end - mid), lineWidthRounded, _st.inactiveFg);
|
||||||
|
if (lineWidthPartial > 0.01) {
|
||||||
|
p.setOpacity(masterOpacity * over * lineWidthPartial);
|
||||||
|
p.fillRect(mid, height() - lineWidthRounded - 1, (end - mid), 1, _st.inactiveFg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Ui
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop 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 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It 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.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ui/widgets/continuous_slider.h"
|
||||||
|
|
||||||
|
namespace style {
|
||||||
|
struct FilledSlider;
|
||||||
|
} // namespace style
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
class FilledSlider : public ContinuousSlider {
|
||||||
|
public:
|
||||||
|
FilledSlider(QWidget *parent, const style::FilledSlider &st);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QRect getSeekRect() const override;
|
||||||
|
float64 getOverDuration() const override;
|
||||||
|
|
||||||
|
const style::FilledSlider &_st;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Ui
|
|
@ -25,148 +25,78 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
|
||||||
MediaSlider::MediaSlider(QWidget *parent, const style::MediaSlider &st) : TWidget(parent)
|
MediaSlider::MediaSlider(QWidget *parent, const style::MediaSlider &st) : ContinuousSlider(parent)
|
||||||
, _st(st)
|
, _st(st) {
|
||||||
, _a_value(animation(this, &MediaSlider::step_value)) {
|
|
||||||
setCursor(style::cur_pointer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float64 MediaSlider::value() const {
|
QRect MediaSlider::getSeekRect() const {
|
||||||
return a_value.current();
|
return isHorizontal()
|
||||||
|
? QRect(_st.seekSize.width() / 2, 0, width() - _st.seekSize.width(), height())
|
||||||
|
: QRect(0, _st.seekSize.height() / 2, width(), height() - _st.seekSize.width());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaSlider::setDisabled(bool disabled) {
|
float64 MediaSlider::getOverDuration() const {
|
||||||
if (_disabled != disabled) {
|
return _st.duration;
|
||||||
_disabled = disabled;
|
|
||||||
setCursor(_disabled ? style::cur_default : style::cur_pointer);
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MediaSlider::setValue(float64 value, bool animated) {
|
|
||||||
if (animated) {
|
|
||||||
a_value.start(value);
|
|
||||||
_a_value.start();
|
|
||||||
} else {
|
|
||||||
a_value = anim::fvalue(value, value);
|
|
||||||
_a_value.stop();
|
|
||||||
}
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MediaSlider::setFadeOpacity(float64 opacity) {
|
|
||||||
_fadeOpacity = opacity;
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MediaSlider::step_value(float64 ms, bool timer) {
|
|
||||||
float64 dt = ms / (2 * AudioVoiceMsgUpdateView);
|
|
||||||
if (dt >= 1) {
|
|
||||||
_a_value.stop();
|
|
||||||
a_value.finish();
|
|
||||||
} else {
|
|
||||||
a_value.update(qMin(dt, 1.), anim::linear);
|
|
||||||
}
|
|
||||||
if (timer) update();
|
|
||||||
}
|
|
||||||
|
|
||||||
int MediaSlider::lineLeft() const {
|
|
||||||
return (_st.seekSize.width() / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
int MediaSlider::lineWidth() const {
|
|
||||||
return (width() - _st.seekSize.width());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaSlider::paintEvent(QPaintEvent *e) {
|
void MediaSlider::paintEvent(QPaintEvent *e) {
|
||||||
Painter p(this);
|
Painter p(this);
|
||||||
|
|
||||||
int radius = _st.width / 2;
|
|
||||||
p.setOpacity(_fadeOpacity);
|
|
||||||
p.setPen(Qt::NoPen);
|
p.setPen(Qt::NoPen);
|
||||||
p.setRenderHint(QPainter::HighQualityAntialiasing);
|
p.setRenderHint(QPainter::HighQualityAntialiasing);
|
||||||
|
|
||||||
|
auto horizontal = isHorizontal();
|
||||||
auto ms = getms();
|
auto ms = getms();
|
||||||
_a_value.step(ms);
|
auto masterOpacity = fadeOpacity();
|
||||||
auto over = _a_over.current(ms, _over ? 1. : 0.);
|
auto radius = _st.width / 2;
|
||||||
int skip = lineLeft();
|
auto disabled = isDisabled();
|
||||||
int length = lineWidth();
|
auto over = getCurrentOverFactor(ms);
|
||||||
float64 prg = _mouseDown ? _downValue : a_value.current();
|
auto seekRect = getSeekRect();
|
||||||
int32 from = skip, mid = _disabled ? 0 : qRound(from + prg * length), end = from + length;
|
auto value = getCurrentValue(ms);
|
||||||
|
|
||||||
|
// invert colors and value for vertical
|
||||||
|
if (!horizontal) value = 1. - value;
|
||||||
|
|
||||||
|
auto markerFrom = (horizontal ? seekRect.x() : seekRect.y());
|
||||||
|
auto markerLength = (horizontal ? seekRect.width() : seekRect.height());
|
||||||
|
auto from = _alwaysDisplayMarker ? 0 : markerFrom;
|
||||||
|
auto length = _alwaysDisplayMarker ? (horizontal ? width() : height()) : markerLength;
|
||||||
|
auto mid = disabled ? from : qRound(from + value * length);
|
||||||
|
auto end = from + length;
|
||||||
if (mid > from) {
|
if (mid > from) {
|
||||||
p.setClipRect(0, 0, mid, height());
|
auto fromClipRect = horizontal ? QRect(0, 0, mid, height()) : QRect(0, 0, width(), mid);
|
||||||
p.setOpacity(_fadeOpacity * (over * _st.activeOpacity + (1. - over) * _st.inactiveOpacity));
|
auto fromRect = horizontal
|
||||||
p.setBrush(_st.activeFg);
|
? QRect(from, (height() - _st.width) / 2, mid + radius - from, _st.width)
|
||||||
p.drawRoundedRect(from, (height() - _st.width) / 2, mid + radius - from, _st.width, radius, radius);
|
: QRect((width() - _st.width) / 2, from, _st.width, mid + radius - from);
|
||||||
|
p.setClipRect(fromClipRect);
|
||||||
|
p.setOpacity(masterOpacity * (over * _st.activeOpacity + (1. - over) * _st.inactiveOpacity));
|
||||||
|
p.setBrush(horizontal ? _st.activeFg : _st.inactiveFg);
|
||||||
|
p.drawRoundedRect(fromRect, radius, radius);
|
||||||
}
|
}
|
||||||
if (end > mid) {
|
if (end > mid) {
|
||||||
p.setClipRect(mid, 0, width() - mid, height());
|
auto endClipRect = horizontal ? QRect(mid, 0, width() - mid, height()) : QRect(0, mid, width(), height() - mid);
|
||||||
p.setOpacity(_fadeOpacity);
|
auto endRect = horizontal
|
||||||
p.setBrush(_st.inactiveFg);
|
? QRect(mid - radius, (height() - _st.width) / 2, end - (mid - radius), _st.width)
|
||||||
p.drawRoundedRect(mid - radius, (height() - _st.width) / 2, end - (mid - radius), _st.width, radius, radius);
|
: QRect((width() - _st.width) / 2, mid - radius, _st.width, end - (mid - radius));
|
||||||
|
p.setClipRect(endClipRect);
|
||||||
|
p.setOpacity(masterOpacity);
|
||||||
|
p.setBrush(horizontal ? _st.inactiveFg : _st.activeFg);
|
||||||
|
p.drawRoundedRect(endRect, radius, radius);
|
||||||
}
|
}
|
||||||
if (!_disabled && over > 0) {
|
auto markerSizeRatio = disabled ? 0. : (_alwaysDisplayMarker ? 1. : over);
|
||||||
int x = mid - skip;
|
if (markerSizeRatio > 0) {
|
||||||
p.setClipRect(rect());
|
auto position = qRound(markerFrom + value * markerLength) - (horizontal ? seekRect.x() : seekRect.y());
|
||||||
p.setOpacity(_fadeOpacity * _st.activeOpacity);
|
auto seekButton = horizontal
|
||||||
auto seekButton = QRect(x, (height() - _st.seekSize.height()) / 2, _st.seekSize.width(), _st.seekSize.height());
|
? QRect(position, (height() - _st.seekSize.height()) / 2, _st.seekSize.width(), _st.seekSize.height())
|
||||||
int remove = ((1. - over) * _st.seekSize.width()) / 2.;
|
: QRect((width() - _st.seekSize.width()) / 2, position, _st.seekSize.width(), _st.seekSize.height());
|
||||||
if (remove * 2 < _st.seekSize.width()) {
|
auto size = horizontal ? _st.seekSize.width() : _st.seekSize.height();
|
||||||
|
auto remove = static_cast<int>(((1. - markerSizeRatio) * size) / 2.);
|
||||||
|
if (remove * 2 < size) {
|
||||||
|
p.setClipRect(rect());
|
||||||
|
p.setOpacity(masterOpacity * _st.activeOpacity);
|
||||||
p.setBrush(_st.activeFg);
|
p.setBrush(_st.activeFg);
|
||||||
p.drawEllipse(seekButton.marginsRemoved(QMargins(remove, remove, remove, remove)));
|
p.drawEllipse(seekButton.marginsRemoved(QMargins(remove, remove, remove, remove)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaSlider::mouseMoveEvent(QMouseEvent *e) {
|
|
||||||
if (_mouseDown) {
|
|
||||||
updateDownValueFromPos(e->pos().x());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MediaSlider::mousePressEvent(QMouseEvent *e) {
|
|
||||||
_mouseDown = true;
|
|
||||||
_downValue = snap((e->pos().x() - lineLeft()) / float64(lineWidth()), 0., 1.);
|
|
||||||
update();
|
|
||||||
if (_changeProgressCallback) {
|
|
||||||
_changeProgressCallback(_downValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MediaSlider::mouseReleaseEvent(QMouseEvent *e) {
|
|
||||||
if (_mouseDown) {
|
|
||||||
_mouseDown = false;
|
|
||||||
if (_changeFinishedCallback) {
|
|
||||||
_changeFinishedCallback(_downValue);
|
|
||||||
}
|
|
||||||
a_value = anim::fvalue(_downValue, _downValue);
|
|
||||||
_a_value.stop();
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MediaSlider::updateDownValueFromPos(int pos) {
|
|
||||||
_downValue = snap((pos - lineLeft()) / float64(lineWidth()), 0., 1.);
|
|
||||||
update();
|
|
||||||
if (_changeProgressCallback) {
|
|
||||||
_changeProgressCallback(_downValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MediaSlider::enterEvent(QEvent *e) {
|
|
||||||
setOver(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MediaSlider::leaveEvent(QEvent *e) {
|
|
||||||
setOver(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MediaSlider::setOver(bool over) {
|
|
||||||
if (_over == over) return;
|
|
||||||
|
|
||||||
_over = over;
|
|
||||||
auto from = _over ? 0. : 1., to = _over ? 1. : 0.;
|
|
||||||
_a_over.start([this] { update(); }, from, to, _st.duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
|
@ -20,62 +20,32 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "ui/widgets/continuous_slider.h"
|
||||||
|
|
||||||
namespace style {
|
namespace style {
|
||||||
struct MediaSlider;
|
struct MediaSlider;
|
||||||
} // namespace style
|
} // namespace style
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
|
||||||
class MediaSlider : public TWidget {
|
class MediaSlider : public ContinuousSlider {
|
||||||
public:
|
public:
|
||||||
MediaSlider(QWidget *parent, const style::MediaSlider &st);
|
MediaSlider(QWidget *parent, const style::MediaSlider &st);
|
||||||
|
|
||||||
float64 value() const;
|
void setAlwaysDisplayMarker(bool alwaysDisplayMarker) {
|
||||||
void setValue(float64 value, bool animated);
|
_alwaysDisplayMarker = alwaysDisplayMarker;
|
||||||
void setFadeOpacity(float64 opacity);
|
update();
|
||||||
void setDisabled(bool disabled);
|
|
||||||
|
|
||||||
using Callback = base::lambda_unique<void(float64)>;
|
|
||||||
void setChangeProgressCallback(Callback &&callback) {
|
|
||||||
_changeProgressCallback = std_::move(callback);
|
|
||||||
}
|
|
||||||
void setChangeFinishedCallback(Callback &&callback) {
|
|
||||||
_changeFinishedCallback = std_::move(callback);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent *e) override;
|
void paintEvent(QPaintEvent *e) override;
|
||||||
void mouseMoveEvent(QMouseEvent *e) override;
|
|
||||||
void mousePressEvent(QMouseEvent *e) override;
|
|
||||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
|
||||||
void enterEvent(QEvent *e) override;
|
|
||||||
void leaveEvent(QEvent *e) override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void step_value(float64 ms, bool timer);
|
QRect getSeekRect() const override;
|
||||||
void setOver(bool over);
|
float64 getOverDuration() const override;
|
||||||
void updateDownValueFromPos(int pos);
|
|
||||||
|
|
||||||
int lineLeft() const;
|
|
||||||
int lineWidth() const;
|
|
||||||
|
|
||||||
const style::MediaSlider &_st;
|
const style::MediaSlider &_st;
|
||||||
|
bool _alwaysDisplayMarker = false;
|
||||||
bool _disabled = false;
|
|
||||||
|
|
||||||
Callback _changeProgressCallback;
|
|
||||||
Callback _changeFinishedCallback;
|
|
||||||
|
|
||||||
bool _over = false;
|
|
||||||
FloatAnimation _a_over;
|
|
||||||
|
|
||||||
anim::fvalue a_value = { 0., 0. };
|
|
||||||
Animation _a_value;
|
|
||||||
|
|
||||||
bool _mouseDown = false;
|
|
||||||
float64 _downValue = 0.;
|
|
||||||
|
|
||||||
float64 _fadeOpacity = 1.;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop 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 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It 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.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "ui/widgets/shadow.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
void ToggleableShadow::setMode(Mode mode) {
|
||||||
|
if (mode == Mode::ShownFast || mode == Mode::HiddenFast) {
|
||||||
|
if (!_a_opacity.animating()) {
|
||||||
|
_a_opacity.finish();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_shown && (mode == Mode::Hidden || mode == Mode::HiddenFast)) {
|
||||||
|
_shown = false;
|
||||||
|
if (mode == Mode::Hidden) {
|
||||||
|
_a_opacity.start([this] { update(); }, 1., 0., st::shadowToggleDuration);
|
||||||
|
}
|
||||||
|
} else if (!_shown && (mode == Mode::Shown || mode == Mode::ShownFast)) {
|
||||||
|
_shown = true;
|
||||||
|
if (mode == Mode::Shown) {
|
||||||
|
_a_opacity.start([this] { update(); }, 0., 1., st::shadowToggleDuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToggleableShadow::paintEvent(QPaintEvent *e) {
|
||||||
|
Painter p(this);
|
||||||
|
if (_a_opacity.animating(getms())) {
|
||||||
|
p.setOpacity(_a_opacity.current());
|
||||||
|
} else if (!_shown) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
p.fillRect(e->rect(), _color);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Ui
|
|
@ -0,0 +1,47 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
class PlainShadow : public TWidget {
|
||||||
|
public:
|
||||||
|
PlainShadow(QWidget *parent, const style::color &color) : TWidget(parent), _color(color) {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *e) override {
|
||||||
|
Painter(this).fillRect(e->rect(), _color->b);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const style::color &_color;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class ToggleableShadow : public TWidget {
|
||||||
|
public:
|
||||||
|
ToggleableShadow(QWidget *parent, const style::color &color) : TWidget(parent), _color(color) {
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Mode {
|
||||||
|
Shown,
|
||||||
|
ShownFast,
|
||||||
|
Hidden,
|
||||||
|
HiddenFast
|
||||||
|
};
|
||||||
|
void setMode(Mode mode);
|
||||||
|
|
||||||
|
bool isFullyShown() const {
|
||||||
|
return _shown && !_a_opacity.animating();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const style::color &_color;
|
||||||
|
FloatAnimation _a_opacity;
|
||||||
|
bool _shown = true;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Ui
|
|
@ -27,19 +27,20 @@ namespace Ui {
|
||||||
template <typename Widget>
|
template <typename Widget>
|
||||||
class WidgetSlideWrap : public TWidget {
|
class WidgetSlideWrap : public TWidget {
|
||||||
public:
|
public:
|
||||||
|
using UpdateCallback = base::lambda_unique<void()>;
|
||||||
WidgetSlideWrap(QWidget *parent, Widget *entity
|
WidgetSlideWrap(QWidget *parent, Widget *entity
|
||||||
, style::margins entityPadding
|
, style::margins entityPadding
|
||||||
, base::lambda_unique<void()> &&updateCallback
|
, UpdateCallback &&updateCallback
|
||||||
, int duration = st::widgetSlideDuration) : TWidget(parent)
|
, int duration = st::widgetSlideDuration) : TWidget(parent)
|
||||||
, _entity(entity)
|
, _entity(entity)
|
||||||
, _padding(entityPadding)
|
, _padding(entityPadding)
|
||||||
, _duration(duration)
|
, _duration(duration)
|
||||||
, _updateCallback(std_::move(updateCallback))
|
, _updateCallback(std_::move(updateCallback))
|
||||||
, _a_height(animation(this, &WidgetSlideWrap<Widget>::step_height)) {
|
, _a_height(animation(this, &WidgetSlideWrap<Widget>::step_height)) {
|
||||||
entity->setParent(this);
|
_entity->setParent(this);
|
||||||
entity->moveToLeft(_padding.left(), _padding.top());
|
_entity->moveToLeft(_padding.left(), _padding.top());
|
||||||
_realSize = entity->rect().marginsAdded(_padding).size();
|
_realSize = _entity->rect().marginsAdded(_padding).size();
|
||||||
entity->installEventFilter(this);
|
_entity->installEventFilter(this);
|
||||||
resize(_realSize);
|
resize(_realSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +92,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void showFast() {
|
void showFast() {
|
||||||
|
show();
|
||||||
_a_height.stop();
|
_a_height.stop();
|
||||||
resize(_realSize);
|
resize(_realSize);
|
||||||
if (_updateCallback) {
|
if (_updateCallback) {
|
||||||
|
@ -152,7 +154,7 @@ private:
|
||||||
bool _inResizeToWidth = false;
|
bool _inResizeToWidth = false;
|
||||||
style::margins _padding;
|
style::margins _padding;
|
||||||
int _duration;
|
int _duration;
|
||||||
base::lambda_unique<void()> _updateCallback;
|
UpdateCallback _updateCallback;
|
||||||
|
|
||||||
style::size _realSize;
|
style::size _realSize;
|
||||||
int _forceHeight = -1;
|
int _forceHeight = -1;
|
||||||
|
|
|
@ -43,6 +43,14 @@ MediaSlider {
|
||||||
duration: int;
|
duration: int;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FilledSlider {
|
||||||
|
fullWidth: pixels;
|
||||||
|
lineWidth: pixels;
|
||||||
|
activeFg: color;
|
||||||
|
inactiveFg: color;
|
||||||
|
duration: int;
|
||||||
|
}
|
||||||
|
|
||||||
widgetSlideDuration: 200;
|
widgetSlideDuration: 200;
|
||||||
|
|
||||||
discreteSliderHeight: 39px;
|
discreteSliderHeight: 39px;
|
||||||
|
|
|
@ -83,7 +83,7 @@ void ChatBackground::setTile(bool tile) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ChatBackground *chatBackground() {
|
ChatBackground *chatBackground() {
|
||||||
instance.makeIfNull();
|
instance.createIfNull();
|
||||||
return instance.data();
|
return instance.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ internal::Widget::Direction notificationShiftDirection() {
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void start() {
|
void start() {
|
||||||
ManagerInstance.makeIfNull();
|
ManagerInstance.createIfNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager *manager() {
|
Manager *manager() {
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop 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 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It 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.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "window/player_wrap_widget.h"
|
||||||
|
|
||||||
|
#include "ui/widgets/shadow.h"
|
||||||
|
|
||||||
|
namespace Window {
|
||||||
|
|
||||||
|
PlayerWrapWidget::PlayerWrapWidget(QWidget *parent, UpdateCallback &&updateCallback) : Parent(parent
|
||||||
|
, new Media::Player::Widget(parent)
|
||||||
|
, style::margins(0, 0, 0, 0)
|
||||||
|
, std_::move(updateCallback)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerWrapWidget::resizeEvent(QResizeEvent *e) {
|
||||||
|
updateShadowGeometry();
|
||||||
|
Parent::resizeEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerWrapWidget::updateShadowGeometry() {
|
||||||
|
auto skip = Adaptive::OneColumn() ? 0 : st::lineWidth;
|
||||||
|
entity()->setShadowGeometryToLeft(skip, height() - st::lineWidth, width() - skip, st::lineWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Window
|
|
@ -0,0 +1,40 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ui/widgets/widget_slide_wrap.h"
|
||||||
|
#include "media/player/media_player_widget.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class PlainShadow;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
|
namespace Window {
|
||||||
|
|
||||||
|
class PlayerWrapWidget : public Ui::WidgetSlideWrap<Media::Player::Widget> {
|
||||||
|
using Parent = Ui::WidgetSlideWrap<Media::Player::Widget>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using UpdateCallback = Parent::UpdateCallback;
|
||||||
|
PlayerWrapWidget(QWidget *parent, UpdateCallback &&updateCallback);
|
||||||
|
|
||||||
|
void updateAdaptiveLayout() {
|
||||||
|
updateShadowGeometry();
|
||||||
|
}
|
||||||
|
void showShadow() {
|
||||||
|
entity()->showShadow();
|
||||||
|
}
|
||||||
|
void hideShadow() {
|
||||||
|
entity()->hideShadow();
|
||||||
|
}
|
||||||
|
int contentHeight() const {
|
||||||
|
return height() - st::lineWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateShadowGeometry();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Window
|
|
@ -129,8 +129,6 @@
|
||||||
'<(src_loc)/overviewwidget.h',
|
'<(src_loc)/overviewwidget.h',
|
||||||
'<(src_loc)/passcodewidget.cpp',
|
'<(src_loc)/passcodewidget.cpp',
|
||||||
'<(src_loc)/passcodewidget.h',
|
'<(src_loc)/passcodewidget.h',
|
||||||
'<(src_loc)/playerwidget.cpp',
|
|
||||||
'<(src_loc)/playerwidget.h',
|
|
||||||
'<(src_loc)/localimageloader.cpp',
|
'<(src_loc)/localimageloader.cpp',
|
||||||
'<(src_loc)/localimageloader.h',
|
'<(src_loc)/localimageloader.h',
|
||||||
'<(src_loc)/localstorage.cpp',
|
'<(src_loc)/localstorage.cpp',
|
||||||
|
@ -268,6 +266,8 @@
|
||||||
'<(src_loc)/media/player/media_player_instance.h',
|
'<(src_loc)/media/player/media_player_instance.h',
|
||||||
'<(src_loc)/media/player/media_player_list.cpp',
|
'<(src_loc)/media/player/media_player_list.cpp',
|
||||||
'<(src_loc)/media/player/media_player_list.h',
|
'<(src_loc)/media/player/media_player_list.h',
|
||||||
|
'<(src_loc)/media/player/media_player_panel.cpp',
|
||||||
|
'<(src_loc)/media/player/media_player_panel.h',
|
||||||
'<(src_loc)/media/player/media_player_title_button.cpp',
|
'<(src_loc)/media/player/media_player_title_button.cpp',
|
||||||
'<(src_loc)/media/player/media_player_title_button.h',
|
'<(src_loc)/media/player/media_player_title_button.h',
|
||||||
'<(src_loc)/media/player/media_player_volume_controller.cpp',
|
'<(src_loc)/media/player/media_player_volume_controller.cpp',
|
||||||
|
@ -467,13 +467,19 @@
|
||||||
'<(src_loc)/ui/toast/toast_manager.h',
|
'<(src_loc)/ui/toast/toast_manager.h',
|
||||||
'<(src_loc)/ui/toast/toast_widget.cpp',
|
'<(src_loc)/ui/toast/toast_widget.cpp',
|
||||||
'<(src_loc)/ui/toast/toast_widget.h',
|
'<(src_loc)/ui/toast/toast_widget.h',
|
||||||
|
'<(src_loc)/ui/widgets/continuous_slider.cpp',
|
||||||
|
'<(src_loc)/ui/widgets/continuous_slider.h',
|
||||||
|
'<(src_loc)/ui/widgets/discrete_slider.cpp',
|
||||||
|
'<(src_loc)/ui/widgets/discrete_slider.h',
|
||||||
|
'<(src_loc)/ui/widgets/filled_slider.cpp',
|
||||||
|
'<(src_loc)/ui/widgets/filled_slider.h',
|
||||||
'<(src_loc)/ui/widgets/label_simple.cpp',
|
'<(src_loc)/ui/widgets/label_simple.cpp',
|
||||||
'<(src_loc)/ui/widgets/label_simple.h',
|
'<(src_loc)/ui/widgets/label_simple.h',
|
||||||
'<(src_loc)/ui/widgets/media_slider.cpp',
|
'<(src_loc)/ui/widgets/media_slider.cpp',
|
||||||
'<(src_loc)/ui/widgets/media_slider.h',
|
'<(src_loc)/ui/widgets/media_slider.h',
|
||||||
|
'<(src_loc)/ui/widgets/shadow.cpp',
|
||||||
|
'<(src_loc)/ui/widgets/shadow.h',
|
||||||
'<(src_loc)/ui/widgets/widget_slide_wrap.h',
|
'<(src_loc)/ui/widgets/widget_slide_wrap.h',
|
||||||
'<(src_loc)/ui/widgets/discrete_slider.cpp',
|
|
||||||
'<(src_loc)/ui/widgets/discrete_slider.h',
|
|
||||||
'<(src_loc)/ui/animation.cpp',
|
'<(src_loc)/ui/animation.cpp',
|
||||||
'<(src_loc)/ui/animation.h',
|
'<(src_loc)/ui/animation.h',
|
||||||
'<(src_loc)/ui/button.cpp',
|
'<(src_loc)/ui/button.cpp',
|
||||||
|
@ -514,6 +520,8 @@
|
||||||
'<(src_loc)/window/notifications_manager_default.h',
|
'<(src_loc)/window/notifications_manager_default.h',
|
||||||
'<(src_loc)/window/notifications_utilities.cpp',
|
'<(src_loc)/window/notifications_utilities.cpp',
|
||||||
'<(src_loc)/window/notifications_utilities.h',
|
'<(src_loc)/window/notifications_utilities.h',
|
||||||
|
'<(src_loc)/window/player_wrap_widget.cpp',
|
||||||
|
'<(src_loc)/window/player_wrap_widget.h',
|
||||||
'<(src_loc)/window/section_widget.cpp',
|
'<(src_loc)/window/section_widget.cpp',
|
||||||
'<(src_loc)/window/section_widget.h',
|
'<(src_loc)/window/section_widget.h',
|
||||||
'<(src_loc)/window/slide_animation.cpp',
|
'<(src_loc)/window/slide_animation.cpp',
|
||||||
|
|