diff --git a/Telegram/Resources/basic.style b/Telegram/Resources/basic.style index 866c893347..8245a63142 100644 --- a/Telegram/Resources/basic.style +++ b/Telegram/Resources/basic.style @@ -55,10 +55,13 @@ wndMinWidth: 380px; adaptiveNormalWidth: 640px; adaptiveWideWidth: 1366px; +windowBg: #fff; // fallback for background: white +windowTextFg: #000; // fallback for text color: black +windowSubTextFg: #8a8a8a; // fallback for subtext color: gray + wndMinHeight: 480px; wndDefWidth: 800px; wndDefHeight: 600px; -wndBG: white; wndShadow: sprite(209px, 46px, 19px, 19px); wndShadowShift: 1px; @@ -1671,13 +1674,13 @@ confirmCompressedSkip: 10px; profileMaxWidth: 410px; profilePadding: margins(28px, 30px, 28px, 0px); -profilePhotoSize: 120px; -profileNameLeft: 21px; -profileNameTop: -1px; -profileNameFont: font(20px); -profileStatusLeft: 22px; -profileStatusTop: 31px; -profileStatusFont: font(fsize); +//profilePhotoSize: 120px; +//profileNameLeft: 21px; +//profileNameTop: -1px; +//profileNameFont: font(20px); +//profileStatusLeft: 22px; +//profileStatusTop: 31px; +//profileStatusFont: font(fsize); profilePhoneLeft: 22px; profilePhoneTop: 62px; profilePhoneFont: font(16px); @@ -2458,7 +2461,7 @@ inlineResultsSkip: 3px; inlineMediaHeight: 96px; inlineThumbSize: 64px; inlineThumbSkip: 10px; -inlineDescriptionFg: #8a8a8a; +inlineDescriptionFg: windowSubTextFg; inlineRowMargin: 6px; inlineRowBorder: 1px; inlineRowBorderFg: #eaeaea; diff --git a/Telegram/Resources/icons/topbar_back_arrow.png b/Telegram/Resources/icons/topbar_back_arrow.png new file mode 100644 index 0000000000..7c62fd73de Binary files /dev/null and b/Telegram/Resources/icons/topbar_back_arrow.png differ diff --git a/Telegram/Resources/icons/topbar_back_arrow@2x.png b/Telegram/Resources/icons/topbar_back_arrow@2x.png new file mode 100644 index 0000000000..990a5bb66e Binary files /dev/null and b/Telegram/Resources/icons/topbar_back_arrow@2x.png differ diff --git a/Telegram/SourceFiles/core/basic_types.h b/Telegram/SourceFiles/core/basic_types.h index 0e2d05e645..aa4f955b44 100644 --- a/Telegram/SourceFiles/core/basic_types.h +++ b/Telegram/SourceFiles/core/basic_types.h @@ -911,15 +911,6 @@ private: }; -template -inline void destroyImplementation(I *&ptr) { - if (ptr) { - ptr->destroy(); - ptr = 0; - } - deleteAndMark(ptr); -} - class Composer; typedef void(*ComponentConstruct)(void *location, Composer *composer); typedef void(*ComponentDestruct)(void *location); @@ -1154,213 +1145,88 @@ public: virtual R call(Args... args) const = 0; virtual ~SharedCallback() { } - typedef QSharedPointer> Ptr; + using Ptr = QSharedPointer>; + }; -template +template class FunctionImplementation { public: - virtual R call() = 0; + virtual R call(Args... args) = 0; virtual void destroy() { delete this; } virtual ~FunctionImplementation() {} + }; -template -class NullFunctionImplementation : public FunctionImplementation { + +template +class NullFunctionImplementation : public FunctionImplementation { public: - virtual R call() { return R(); } + virtual R call(Args... args) { return R(); } virtual void destroy() {} - static NullFunctionImplementation SharedInstance; + static NullFunctionImplementation SharedInstance; + }; -template -NullFunctionImplementation NullFunctionImplementation::SharedInstance; -template -class FunctionCreator { -public: - FunctionCreator(FunctionImplementation *ptr) : _ptr(ptr) {} - FunctionCreator(const FunctionCreator &other) : _ptr(other.create()) {} - FunctionImplementation *create() const { return getPointerAndReset(_ptr); } - ~FunctionCreator() { destroyImplementation(_ptr); } -private: - FunctionCreator &operator=(const FunctionCreator &other); - mutable FunctionImplementation *_ptr; -}; -template +template +NullFunctionImplementation NullFunctionImplementation::SharedInstance; + +template class Function { public: - typedef FunctionCreator Creator; - static Creator Null() { return Creator(&NullFunctionImplementation::SharedInstance); } - Function(const Creator &creator) : _implementation(creator.create()) {} - R call() { return _implementation->call(); } - ~Function() { destroyImplementation(_implementation); } + Function() : _implementation(&NullFunctionImplementation::SharedInstance) {} + Function(FunctionImplementation *implementation) : _implementation(implementation) {} + Function(const Function &other) = delete; + Function &operator=(const Function &other) = delete; + Function(Function &&other) : _implementation(other._implementation) { + other._implementation = &NullFunctionImplementation::SharedInstance; + } + Function &operator=(Function &&other) { + std::swap(_implementation, other._implementation); + return *this; + } + + R call(Args... args) { return _implementation->call(args...); } + ~Function() { + if (_implementation) { + _implementation->destroy(); + _implementation = nullptr; + } + deleteAndMark(_implementation); + } + private: - Function(const Function &other); - Function &operator=(const Function &other); - FunctionImplementation *_implementation; + FunctionImplementation *_implementation; + }; -template -class WrappedFunction : public FunctionImplementation { +template +class WrappedFunction : public FunctionImplementation { public: - typedef R(*Method)(); + using Method = R(*)(Args... args); WrappedFunction(Method method) : _method(method) {} - virtual R call() { return (*_method)(); } + virtual R call(Args... args) { return (*_method)(args...); } + private: Method _method; + }; -template -inline FunctionCreator func(R(*method)()) { - return FunctionCreator(new WrappedFunction(method)); +template +inline Function func(R(*method)(Args... args)) { + return Function(new WrappedFunction(method)); } -template -class ObjectFunction : public FunctionImplementation { + +template +class ObjectFunction : public FunctionImplementation { public: - typedef R(I::*Method)(); + using Method = R(I::*)(Args... args); ObjectFunction(O *obj, Method method) : _obj(obj), _method(method) {} - virtual R call() { return (_obj->*_method)(); } + virtual R call(Args... args) { return (_obj->*_method)(args...); } + private: O *_obj; Method _method; -}; -template -inline FunctionCreator func(O *obj, R(I::*method)()) { - return FunctionCreator(new ObjectFunction(obj, method)); -} -template -class Function1Implementation { -public: - virtual R call(A1 a1) = 0; - virtual void destroy() { delete this; } - virtual ~Function1Implementation() {} }; -template -class NullFunction1Implementation : public Function1Implementation { -public: - virtual R call(A1 a1) { return R(); } - virtual void destroy() {} - static NullFunction1Implementation SharedInstance; -}; -template -NullFunction1Implementation NullFunction1Implementation::SharedInstance; -template -class Function1Creator { -public: - Function1Creator(Function1Implementation *ptr) : _ptr(ptr) {} - Function1Creator(const Function1Creator &other) : _ptr(other.create()) {} - Function1Implementation *create() const { return getPointerAndReset(_ptr); } - ~Function1Creator() { destroyImplementation(_ptr); } -private: - Function1Creator &operator=(const Function1Creator &other); - mutable Function1Implementation *_ptr; -}; -template -class Function1 { -public: - typedef Function1Creator Creator; - static Creator Null() { return Creator(&NullFunction1Implementation::SharedInstance); } - Function1(const Creator &creator) : _implementation(creator.create()) {} - R call(A1 a1) { return _implementation->call(a1); } - ~Function1() { _implementation->destroy(); } -private: - Function1(const Function1 &other); - Function1 &operator=(const Function1 &other); - Function1Implementation *_implementation; -}; - -template -class WrappedFunction1 : public Function1Implementation { -public: - typedef R(*Method)(A1); - WrappedFunction1(Method method) : _method(method) {} - virtual R call(A1 a1) { return (*_method)(a1); } -private: - Method _method; -}; -template -inline Function1Creator func(R(*method)(A1)) { - return Function1Creator(new WrappedFunction1(method)); -} -template -class ObjectFunction1 : public Function1Implementation { -public: - typedef R(I::*Method)(A1); - ObjectFunction1(O *obj, Method method) : _obj(obj), _method(method) {} - virtual R call(A1 a1) { return (_obj->*_method)(a1); } -private: - O *_obj; - Method _method; -}; -template -Function1Creator func(O *obj, R(I::*method)(A1)) { - return Function1Creator(new ObjectFunction1(obj, method)); -} - -template -class Function2Implementation { -public: - virtual R call(A1 a1, A2 a2) = 0; - virtual void destroy() { delete this; } - virtual ~Function2Implementation() {} -}; -template -class NullFunction2Implementation : public Function2Implementation { -public: - virtual R call(A1 a1, A2 a2) { return R(); } - virtual void destroy() {} - static NullFunction2Implementation SharedInstance; -}; -template -NullFunction2Implementation NullFunction2Implementation::SharedInstance; -template -class Function2Creator { -public: - Function2Creator(Function2Implementation *ptr) : _ptr(ptr) {} - Function2Creator(const Function2Creator &other) : _ptr(other.create()) {} - Function2Implementation *create() const { return getPointerAndReset(_ptr); } - ~Function2Creator() { destroyImplementation(_ptr); } -private: - Function2Creator &operator=(const Function2Creator &other); - mutable Function2Implementation *_ptr; -}; -template -class Function2 { -public: - typedef Function2Creator Creator; - static Creator Null() { return Creator(&NullFunction2Implementation::SharedInstance); } - Function2(const Creator &creator) : _implementation(creator.create()) {} - R call(A1 a1, A2 a2) { return _implementation->call(a1, a2); } - ~Function2() { destroyImplementation(_implementation); } -private: - Function2(const Function2 &other); - Function2 &operator=(const Function2 &other); - Function2Implementation *_implementation; -}; - -template -class WrappedFunction2 : public Function2Implementation { -public: - typedef R(*Method)(A1, A2); - WrappedFunction2(Method method) : _method(method) {} - virtual R call(A1 a1, A2 a2) { return (*_method)(a1, a2); } -private: - Method _method; -}; -template -Function2Creator func(R(*method)(A1, A2)) { - return Function2Creator(new WrappedFunction2(method)); -} - -template -class ObjectFunction2 : public Function2Implementation { -public: - typedef R(I::*Method)(A1, A2); - ObjectFunction2(O *obj, Method method) : _obj(obj), _method(method) {} - virtual R call(A1 a1, A2 a2) { return (_obj->*_method)(a1, a2); } -private: - O *_obj; - Method _method; -}; -template -Function2Creator func(O *obj, R(I::*method)(A1, A2)) { - return Function2Creator(new ObjectFunction2(obj, method)); +template +inline Function func(O *obj, R(I::*method)(Args...)) { + return Function(new ObjectFunction(obj, method)); } diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index be5fba8a11..04a8a73294 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -269,6 +269,15 @@ bool hideWindowNoQuit() { return false; } +bool skipPaintEvent(QWidget *widget, QPaintEvent *event) { + if (auto w = App::wnd()) { + if (w->contentOverlapped(widget, event)) { + return true; + } + } + return false; +} + } // namespace Ui namespace Notify { diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index 412c0d65a1..0f16b238ca 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -88,6 +88,8 @@ PeerData *getPeerForMouseAction(); bool hideWindowNoQuit(); +bool skipPaintEvent(QWidget *widget, QPaintEvent *event); + } // namespace Ui enum ClipStopperType { diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index b9e922790b..4cc6b7bec8 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -3204,14 +3204,14 @@ HistoryItem::~HistoryItem() { } } -RadialAnimation::RadialAnimation(AnimationCreator creator) +RadialAnimation::RadialAnimation(AnimationCallbacks &&callbacks) : _firstStart(0) , _lastStart(0) , _lastTime(0) , _opacity(0) , a_arcEnd(0, 0) , a_arcStart(0, FullArcLength) -, _animation(creator) { +, _animation(std_::move(callbacks)) { } diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index 9c850a53ac..46137693d3 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -1623,7 +1623,7 @@ protected: class RadialAnimation { public: - RadialAnimation(AnimationCreator creator); + RadialAnimation(AnimationCallbacks &&callbacks); float64 opacity() const { return _opacity; @@ -1857,9 +1857,9 @@ protected: virtual bool dataLoaded() const = 0; struct AnimationData { - AnimationData(AnimationCreator thumbOverCallbacks, AnimationCreator radialCallbacks) : a_thumbOver(0, 0) - , _a_thumbOver(thumbOverCallbacks) - , radial(radialCallbacks) { + AnimationData(AnimationCallbacks &&thumbOverCallbacks, AnimationCallbacks &&radialCallbacks) : a_thumbOver(0, 0) + , _a_thumbOver(std_::move(thumbOverCallbacks)) + , radial(std_::move(radialCallbacks)) { } anim::fvalue a_thumbOver; Animation _a_thumbOver; diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h index e36bcc3c5d..7095f8828b 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h @@ -107,9 +107,9 @@ private: void clipCallback(ClipReaderNotification notification); struct AnimationData { - AnimationData(AnimationCreator creator) + AnimationData(AnimationCallbacks &&callbacks) : over(false) - , radial(creator) { + , radial(std_::move(callbacks)) { } bool over; FloatAnimation _a_over; @@ -268,9 +268,9 @@ private: } struct AnimationData { - AnimationData(AnimationCreator thumbOverCallbacks, AnimationCreator radialCallbacks) : a_thumbOver(0, 0) - , _a_thumbOver(thumbOverCallbacks) - , radial(radialCallbacks) { + AnimationData(AnimationCallbacks &&thumbOverCallbacks, AnimationCallbacks &&radialCallbacks) : a_thumbOver(0, 0) + , _a_thumbOver(std_::move(thumbOverCallbacks)) + , radial(std_::move(radialCallbacks)) { } anim::fvalue a_thumbOver; Animation _a_thumbOver; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 8565a53f62..11be42bbd3 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -22,6 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "mainwidget.h" #include "ui/buttons/peer_avatar_button.h" +#include "profile/profile_widget.h" #include "window/top_bar_widget.h" #include "apiwrap.h" #include "dialogswidget.h" @@ -377,7 +378,6 @@ void MainWidget::onFilesOrForwardDrop(const PeerId &peer, const QMimeData *data) void MainWidget::rpcClear() { _history->rpcClear(); _dialogs->rpcClear(); - if (_profile) _profile->rpcClear(); if (_overview) _overview->rpcClear(); if (_api) _api->rpcClear(); RPCSender::rpcClear(); @@ -523,14 +523,23 @@ void MainWidget::noHider(HistoryHider *destroyed) { } onHistoryShown(_history->history(), _history->msgId()); if (_profile || _overview || (_history->peer() && _history->peer()->id)) { - QPixmap animCache = grabInner(), animTopBarCache = grabTopBar(); + QPixmap animCache, animTopBarCache; + if (_profile) { + if (Adaptive::OneColumn()) { + animCache = myGrab(this, QRect(0, _playerHeight, _dialogsWidth, height() - _playerHeight)); + } else { + animCache = myGrab(this, QRect(_dialogsWidth, _playerHeight, width() - _dialogsWidth, height() - _playerHeight)); + } + } else { + animCache = grabInner(); + animTopBarCache = grabTopBar(); + } _dialogs->hide(); if (_overview) { _overview->show(); _overview->animShow(animCache, animTopBarCache); } else if (_profile) { - _profile->show(); - _profile->animShow(animCache, animTopBarCache); + _profile->showAnimated(SlideDirection::FromRight, animCache); } else { _history->show(); _history->animShow(animCache, animTopBarCache); @@ -1187,11 +1196,11 @@ void MainWidget::readServerHistory(History *hist, bool force) { MsgId upTo = hist->inboxRead(0); if (hist->isChannel() && !hist->peer->asChannel()->amIn()) { - return; // no read request for channels that I didn't koin + return; // no read request for channels that I didn't join } ReadRequests::const_iterator i = _readRequests.constFind(hist->peer); - if (i == _readRequests.cend()) { + if (i == _readRequests.cend()) { sendReadRequest(hist->peer, upTo); } else { ReadRequestsPending::iterator i = _readRequestsPending.find(hist->peer); @@ -1282,7 +1291,7 @@ void MainWidget::overviewPreloaded(PeerData *peer, const MTPmessages_Messages &r } void MainWidget::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) { - if (_profile) _profile->mediaOverviewUpdated(peer, type); +// if (_profile) _profile->mediaOverviewUpdated(peer, type); TODO if (!_player->isHidden()) _player->mediaOverviewUpdated(peer, type); if (_overview && (_overview->peer() == peer || _overview->peer()->migrateFrom() == peer)) { _overview->mediaOverviewUpdated(peer, type); @@ -1386,9 +1395,9 @@ void MainWidget::loadMediaBack(PeerData *peer, MediaOverviewType type, bool many } void MainWidget::peerUsernameChanged(PeerData *peer) { - if (_profile && _profile->peer() == peer) { - _profile->peerUsernameChanged(); - } + //if (_profile && _profile->peer() == peer) { TODO + // _profile->peerUsernameChanged(); + //} if (App::settings() && peer == App::self()) { App::settings()->usernameChanged(); } @@ -1695,7 +1704,7 @@ void MainWidget::onParentResize(const QSize &newSize) { void MainWidget::updateOnlineDisplay() { if (this != App::main()) return; _history->updateOnlineDisplay(_history->x(), width() - _history->x() - st::sysBtnDelta * 2 - st::sysCls.img.pxWidth() - st::sysRes.img.pxWidth() - st::sysMin.img.pxWidth()); - if (_profile) _profile->updateOnlineDisplay(); +// if (_profile) _profile->updateOnlineDisplay(); TODO if (App::wnd()->settingsWidget()) App::wnd()->settingsWidget()->updateOnlineDisplay(); } @@ -1883,14 +1892,14 @@ void MainWidget::setInnerFocus() { } else if (_overview) { _overview->activate(); } else if (_profile) { - _profile->activate(); + _profile->setInnerFocus(); } else { dialogsActivate(); } } else if (_overview) { _overview->activate(); } else if (_profile) { - _profile->activate(); + _profile->setInnerFocus(); } else { _history->setInnerFocus(); } @@ -2055,9 +2064,7 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, bool bac if (_profile || _overview) { if (_profile) { _profile->hide(); - _profile->clear(); _profile->deleteLater(); - _profile->rpcClear(); _profile = nullptr; } if (_overview) { @@ -2117,7 +2124,7 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, bool bac PeerData *MainWidget::ui_getPeerForMouseAction() { if (_profile) { - return _profile->ui_getPeerForMouseAction(); + //return _profile->ui_getPeerForMouseAction(); TODO } return _history->ui_getPeerForMouseAction(); } @@ -2201,7 +2208,7 @@ void MainWidget::showMediaOverview(PeerData *peer, MediaOverviewType type, bool if (_overview) { _stack.push_back(new StackItemOverview(_overview->peer(), _overview->type(), _overview->lastWidth(), _overview->lastScrollTop())); } else if (_profile) { - _stack.push_back(new StackItemProfile(_profile->peer(), _profile->lastScrollTop())); +// _stack.push_back(new StackItemProfile(_profile->peer(), _profile->lastScrollTop())); TODO } else if (_history->peer()) { dlgUpdated(); _peerInStack = _history->peer(); @@ -2218,9 +2225,7 @@ void MainWidget::showMediaOverview(PeerData *peer, MediaOverviewType type, bool } if (_profile) { _profile->hide(); - _profile->clear(); _profile->deleteLater(); - _profile->rpcClear(); _profile = nullptr; } _overview = new OverviewWidget(this, peer, type); @@ -2252,12 +2257,18 @@ void MainWidget::showPeerProfile(PeerData *peer, bool back, int32 lastScrollTop) App::wnd()->hideSettings(); if (_profile && _profile->peer() == peer) return; - QPixmap animCache = grabInner(), animTopBarCache = grabTopBar(); + QPixmap animCache; + if (Adaptive::OneColumn()) { + animCache = myGrab(this, QRect(0, _playerHeight, _dialogsWidth, height() - _playerHeight)); + } else { + animCache = myGrab(this, QRect(_dialogsWidth, _playerHeight, width() - _dialogsWidth, height() - _playerHeight)); + } +// QPixmap animCache = grabInner(), animTopBarCache = grabTopBar(); if (!back) { if (_overview) { _stack.push_back(new StackItemOverview(_overview->peer(), _overview->type(), _overview->lastWidth(), _overview->lastScrollTop())); } else if (_profile) { - _stack.push_back(new StackItemProfile(_profile->peer(), _profile->lastScrollTop())); +// _stack.push_back(new StackItemProfile(_profile->peer(), _profile->lastScrollTop())); TODO } else if (_history->peer()) { dlgUpdated(); _peerInStack = _history->peer(); @@ -2275,14 +2286,13 @@ void MainWidget::showPeerProfile(PeerData *peer, bool back, int32 lastScrollTop) } if (_profile) { _profile->hide(); - _profile->clear(); _profile->deleteLater(); - _profile->rpcClear(); + _profile = nullptr; } - _profile = new ProfileWidget(this, peer); - _topBar->show(); + _profile = new Profile::Widget(this, peer); + _topBar->hide(); resizeEvent(0); - _profile->animShow(animCache, animTopBarCache, back, lastScrollTop); + _profile->showAnimated(SlideDirection::FromRight, animCache); _history->animStop(); if (back) clearBotStartToken(_history->peer()); _history->showHistory(0, 0); @@ -2526,7 +2536,9 @@ void MainWidget::showAll() { _dialogs->show(); _history->hide(); } - if (!selectingPeer() && (_profile || _overview || _history->peer())) { + if (_profile) { + _topBar->hide(); + } else if (!selectingPeer() && (_overview || _history->peer())) { _topBar->show(); _dialogs->hide(); } @@ -2547,7 +2559,9 @@ void MainWidget::showAll() { _history->show(); _history->resizeEvent(0); } - if (_profile || _overview || _history->peer()) { + if (_profile) { + _topBar->hide(); + } else if (_overview || _history->peer()) { _topBar->show(); } } @@ -2585,7 +2599,10 @@ void MainWidget::resizeEvent(QResizeEvent *e) { } } _mediaType->moveToLeft(width() - _mediaType->width(), _playerHeight + st::topBarHeight); - if (_profile) _profile->setGeometry(_history->geometry()); + if (_profile) { + QRect profileGeometry(_history->x(), _playerHeight, _history->width(), height() - _playerHeight); + _profile->setGeometryWithTopMoved(profileGeometry, _contentScrollAddToY); + } if (_overview) _overview->setGeometry(_history->geometry()); _contentScrollAddToY = 0; } @@ -2602,7 +2619,7 @@ void MainWidget::updateAdaptiveLayout() { _topBar->updateAdaptiveLayout(); _history->updateAdaptiveLayout(); if (_overview) _overview->updateAdaptiveLayout(); - if (_profile) _profile->updateAdaptiveLayout(); +// if (_profile) _profile->updateAdaptiveLayout(); TODO _player->updateAdaptiveLayout(); } @@ -2612,7 +2629,7 @@ bool MainWidget::needBackButton() { void MainWidget::paintTopBar(Painter &p, float64 over, int32 decreaseWidth) { if (_profile) { - _profile->paintTopBar(p, over, decreaseWidth); +// _profile->paintTopBar(p, over, decreaseWidth); } else if (_overview) { _overview->paintTopBar(p, over, decreaseWidth); } else { @@ -2660,7 +2677,7 @@ PlayerWidget *MainWidget::player() { void MainWidget::onTopBarClick() { if (_profile) { - _profile->topBarClick(); +// _profile->topBarClick(); } else if (_overview) { _overview->topBarClick(); } else { @@ -2669,7 +2686,7 @@ void MainWidget::onTopBarClick() { } void MainWidget::onHistoryShown(History *history, MsgId atMsgId) { - if ((!Adaptive::OneColumn() || !selectingPeer()) && (_profile || _overview || history)) { + if ((!Adaptive::OneColumn() || !selectingPeer()) && (_overview || history)) { _topBar->show(); } else { _topBar->hide(); @@ -3479,7 +3496,7 @@ void MainWidget::startFull(const MTPVector &users) { } void MainWidget::applyNotifySetting(const MTPNotifyPeer &peer, const MTPPeerNotifySettings &settings, History *h) { - PeerData *updatePeer = 0; + PeerData *updatePeer = nullptr; switch (settings.type()) { case mtpc_peerNotifySettingsEmpty: switch (peer.type()) { @@ -3541,9 +3558,9 @@ void MainWidget::applyNotifySetting(const MTPNotifyPeer &peer, const MTPPeerNoti _history->updateNotifySettings(); } _dialogs->updateNotifySettings(updatePeer); - if (_profile && _profile->peer() == updatePeer) { - _profile->updateNotifySettings(); - } + //if (_profile && _profile->peer() == updatePeer) { TODO + // _profile->updateNotifySettings(); + //} } } diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 537b56be57..7bc90af759 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -35,6 +35,10 @@ namespace Window { class TopBarWidget; } // namespace Window +namespace Profile { +class Widget; +} // namespace Profile + class MainWindow; class ApiWrap; class ConfirmBox; @@ -550,7 +554,7 @@ private: ChildWidget _dialogs; ChildWidget _history; - ChildWidget _profile = { nullptr }; + ChildWidget _profile = { nullptr }; ChildWidget _overview = { nullptr }; ChildWidget _player; ChildWidget _topBar; diff --git a/Telegram/SourceFiles/mainwindow.cpp b/Telegram/SourceFiles/mainwindow.cpp index 94277b6a38..daf322fb5d 100644 --- a/Telegram/SourceFiles/mainwindow.cpp +++ b/Telegram/SourceFiles/mainwindow.cpp @@ -435,7 +435,7 @@ void MainWindow::init() { connect(windowHandle(), SIGNAL(activeChanged()), this, SLOT(checkHistoryActivation()), Qt::QueuedConnection); QPalette p(palette()); - p.setColor(QPalette::Window, st::wndBG->c); + p.setColor(QPalette::Window, st::windowBg->c); setPalette(p); title = new TitleWidget(this); @@ -1420,6 +1420,7 @@ void MainWindow::notifySchedule(History *history, HistoryItem *item) { } else if (cOtherOnline() >= t) { delay = Global::NotifyDefaultDelay(); } +// LOG(("Is online: %1, otherOnline: %2, currentTime: %3, otherNotOld: %4, otherLaterThanMe: %5").arg(Logs::b(isOnline)).arg(cOtherOnline()).arg(t).arg(Logs::b(otherNotOld)).arg(Logs::b(otherLaterThanMe))); uint64 when = ms + delay; notifyWhenAlerts[history].insert(when, notifyByFrom); diff --git a/Telegram/SourceFiles/profile/profile.style b/Telegram/SourceFiles/profile/profile.style new file mode 100644 index 0000000000..5ec69df559 --- /dev/null +++ b/Telegram/SourceFiles/profile/profile.style @@ -0,0 +1,50 @@ +/* +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 +*/ +using "basic.style"; + +profileBg: windowBg; + +profileTopBarHeight: topBarHeight; +profileTopBarBackIconFg: #51b3e0; +profileTopBarBackIcon: icon { + { "topbar_back_arrow", profileTopBarBackIconFg }, +}; +profileTopBarBackIconPosition: point(15px, 19px); +profileTopBarBackFont: font(14px); +profileTopBarBackFg: #1485c2; +profileTopBarBackPosition: point(32px, 17px); + +profileMarginTop: 13px; +profilePhotoSize: 112px; +profilePhotoLeft: 35px; +profileNameLeft: 26px; +profileNameTop: 9px; +profileNameFont: font(16px); +profileNameFg: windowTextFg; +profileStatusLeft: 27px; +profileStatusTop: 35px; +profileStatusFont: normalFont; +profileStatusFg: windowSubTextFg; +profileMarginBottom: 30px; +profileSeparator: 10px; + +profileBlocksTop: 7px; +profileBlockMarginTop: 21px; diff --git a/Telegram/SourceFiles/profile/profile_cover.cpp b/Telegram/SourceFiles/profile/profile_cover.cpp new file mode 100644 index 0000000000..c73d0fa150 --- /dev/null +++ b/Telegram/SourceFiles/profile/profile_cover.cpp @@ -0,0 +1,202 @@ +/* +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 "profile/profile_cover.h" + +#include "styles/style_profile.h" +#include "lang.h" +#include "apiwrap.h" +#include "mainwidget.h" + +namespace Profile { + +class BackButton final : public Button { +public: + BackButton(QWidget *parent) : Button(parent) { + setCursor(style::cur_pointer); + } + + void resizeToWidth(int newWidth) { + resize(newWidth, st::profileTopBarHeight); + } + +protected: + void paintEvent(QPaintEvent *e) { + Painter p(this); + + st::profileTopBarBackIcon.paint(p, st::profileTopBarBackIconPosition, width()); + + p.setFont(st::profileTopBarBackFont); + p.setPen(st::profileTopBarBackFg); + p.drawTextLeft(st::profileTopBarBackPosition.x(), st::profileTopBarBackPosition.y(), width(), lang(lng_menu_back)); + } + +private: + +}; + +class PhotoButton final : public Button { +public: + PhotoButton(QWidget *parent, PeerData *peer) : Button(parent), _peer(peer) { + resize(st::profilePhotoSize, st::profilePhotoSize); + } + +protected: + void paintEvent(QPaintEvent *e) { + Painter p(this); + + _peer->paintUserpic(p, st::profilePhotoSize, 0, 0); + } + +private: + PeerData *_peer; + +}; + +CoverWidget::CoverWidget(QWidget *parent, PeerData *peer) : TWidget(parent) +, _peer(peer) +, _peerUser(peer->asUser()) +, _peerChat(peer->asChat()) +, _peerChannel(peer->asChannel()) +, _peerMegagroup(peer->isMegagroup() ? _peerChannel : nullptr) +, _backButton(this) +, _photoButton(this, peer) { + setAttribute(Qt::WA_OpaquePaintEvent); + + _backButton->moveToLeft(0, 0); + connect(_backButton, SIGNAL(clicked()), this, SLOT(onBack())); + + _nameText.setText(st::profileNameFont, App::peerName(_peer)); + updateStatusText(); +} + +void CoverWidget::onBack() { + App::main()->showBackFromStack(); +} + +void CoverWidget::resizeToWidth(int newWidth) { + int newHeight = 0; + + // Top bar + _backButton->resizeToWidth(newWidth); + newHeight += _backButton->height(); + + // Cover content + newHeight += st::profileMarginTop; + _photoButton->moveToLeft(st::profilePhotoLeft, newHeight); + + int infoLeft = _photoButton->x() + _photoButton->width(); + _namePosition = QPoint(infoLeft + st::profileNameLeft, _photoButton->y() + st::profileNameTop); + _statusPosition = QPoint(infoLeft + st::profileStatusLeft, _photoButton->y() + st::profileStatusTop); + + newHeight += st::profilePhotoSize; + newHeight += st::profileMarginBottom; + newHeight += st::profileSeparator; + + newHeight += st::profileBlocksTop; + + resize(newWidth, newHeight); + update(); +} + +void CoverWidget::paintEvent(QPaintEvent *e) { + Painter p(this); + + p.fillRect(e->rect(), st::white); + + int availWidth = width() - _namePosition.x() - _photoButton->x(); + p.setFont(st::profileNameFont); + p.setPen(st::profileNameFg); + _nameText.drawLeftElided(p, _namePosition.x(), _namePosition.y(), availWidth, width()); + + p.setFont(st::profileStatusFont); + p.setPen(st::profileStatusFg); + p.drawTextLeft(_statusPosition.x(), _statusPosition.y(), width(), _statusText); +} + +void CoverWidget::updateStatusText() { + int currentTime = unixtime(); + if (_peerUser) { + _statusText = App::onlineText(_peerUser, currentTime, true); + } else if (_peerChat && _peerChat->amIn()) { + if (_peerChat->noParticipantInfo()) { + App::api()->requestFullPeer(_peer); + if (_statusText.isEmpty()) { + _statusText = lng_chat_status_members(lt_count, _peerChat->count); + } + } else { + int onlineCount = 0; + bool onlyMe = true; + for (auto i = _peerChat->participants.cbegin(), e = _peerChat->participants.cend(); i != e; ++i) { + auto onlineTill = App::onlineForSort(i.key(), currentTime); + if (onlineTill > currentTime) { + ++onlineCount; + } + } + if (onlineCount && !onlyMe) { + _statusText = lng_chat_status_members_online(lt_count, _peerChat->participants.size(), lt_count_online, onlineCount); + } else { + _statusText = lng_chat_status_members(lt_count, _peerChat->participants.size()); + } + } + } else if (isUsingMegagroupOnlineCount()) { + int onlineCount = 0; + bool onlyMe = true; + for_const (auto &user, _peerMegagroup->mgInfo->lastParticipants) { + auto onlineTill = App::onlineForSort(user, currentTime); + if (onlineTill > currentTime) { + ++onlineCount; + } + } + if (onlineCount && !onlyMe) { + _statusText = lng_chat_status_members_online(lt_count, _peerMegagroup->count, lt_count_online, onlineCount); + } else { + _statusText = lng_chat_status_members(lt_count, _peerMegagroup->count); + } + } else if (_peerChannel) { + if (_peerChannel->count > 0) { + _statusText = lng_chat_status_members(lt_count, _peerChannel->count); + } else { + _statusText = lang(_peerChannel->isMegagroup() ? lng_group_status : lng_channel_status); + } + } else { + _statusText = lang(lng_chat_status_unaccessible); + } +} + +bool CoverWidget::isUsingMegagroupOnlineCount() const { + if (!_peerMegagroup || !_peerMegagroup->amIn()) { + return false; + } + + if (_peerMegagroup->count <= 0 || _peerMegagroup->count > Global::ChatSizeMax()) { + return false; + } + + if (_peerMegagroup->mgInfo->lastParticipants.isEmpty() || _peerMegagroup->lastParticipantsCountOutdated()) { + App::api()->requestLastParticipants(_peerMegagroup); + return false; + } + + return true; +} + +} // namespace Profile diff --git a/Telegram/SourceFiles/profile/profile_cover.h b/Telegram/SourceFiles/profile/profile_cover.h new file mode 100644 index 0000000000..c09a309ca8 --- /dev/null +++ b/Telegram/SourceFiles/profile/profile_cover.h @@ -0,0 +1,71 @@ +/* +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 Profile { + +class BackButton; +class PhotoButton; + +class CoverWidget final : public TWidget { + Q_OBJECT + +public: + CoverWidget(QWidget *parent, PeerData *peer); + + // Count new height for width=newWidth and resize to it. + void resizeToWidth(int newWidth); + +public slots: + void onBack(); + +protected: + void paintEvent(QPaintEvent *e) override; + +private: + void updateStatusText(); + bool isUsingMegagroupOnlineCount() const; + + PeerData *_peer; + UserData *_peerUser; + ChatData *_peerChat; + ChannelData *_peerChannel; + ChannelData *_peerMegagroup; + + // Top bar + ChildWidget _backButton; + QList _rightActions; + + // Cover content + ChildWidget _photoButton; + + QPoint _namePosition; + Text _nameText; + + QPoint _statusPosition; + QString _statusText; + + ChildWidget _primaryButton = { nullptr }; + ChildWidget _secondaryButton = { nullptr }; + +}; + +} // namespace Profile diff --git a/Telegram/SourceFiles/profile/profile_inner_widget.cpp b/Telegram/SourceFiles/profile/profile_inner_widget.cpp new file mode 100644 index 0000000000..7d62441d25 --- /dev/null +++ b/Telegram/SourceFiles/profile/profile_inner_widget.cpp @@ -0,0 +1,59 @@ +/* +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 "profile/profile_inner_widget.h" + +#include "styles/style_profile.h" +#include "profile/profile_cover.h" + +namespace Profile { + +InnerWidget::InnerWidget(QWidget *parent, PeerData *peer) : TWidget(parent) +, _peer(peer) +, _cover(this, peer) { +} + +void InnerWidget::resizeToWidth(int newWidth, int minHeight) { + int naturalHeight = resizeGetHeight(newWidth); + _addedHeight = qMax(minHeight - naturalHeight, 0); + resize(newWidth, naturalHeight + _addedHeight); +} + +void InnerWidget::decreaseAdditionalHeight(int removeHeight) { + if (removeHeight > 0) { + resizeToWidth(width(), height() - removeHeight); + } +} + +void InnerWidget::paintEvent(QPaintEvent *e) { + Painter p(this); + + p.fillRect(e->rect(), st::white); +} + +int InnerWidget::resizeGetHeight(int newWidth) { + _cover->resizeToWidth(newWidth); + int newHeight = _cover->height(); + + return newHeight; +} + +} // namespace Profile diff --git a/Telegram/SourceFiles/profile/profile_inner_widget.h b/Telegram/SourceFiles/profile/profile_inner_widget.h new file mode 100644 index 0000000000..5a4368aa03 --- /dev/null +++ b/Telegram/SourceFiles/profile/profile_inner_widget.h @@ -0,0 +1,64 @@ +/* +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 Profile { + +class CoverWidget; +class BlockWidget; + +class InnerWidget final : public TWidget { + Q_OBJECT + +public: + InnerWidget(QWidget *parent, PeerData *peer); + + PeerData *peer() const { + return _peer; + } + + // Count new height for width=newWidth and resize to it. + void resizeToWidth(int newWidth, int minHeight); + + // Sometimes height of this widget is larger than it is required + // so that it is allowed to scroll down to the desired position. + // When resizing with scroll moving up the additional height may be decreased. + void decreaseAdditionalHeight(int removeHeight); + +protected: + void paintEvent(QPaintEvent *e) override; + +private: + // Resizes content and counts natural widget height for the desired width. + int resizeGetHeight(int newWidth); + + PeerData *_peer; + + // Height that we added to the natural height so that it is allowed + // to scroll down to the desired position. + int _addedHeight = 0; + + ChildWidget _cover; + QList _blocks; + +}; + +} // namespace Profile diff --git a/Telegram/SourceFiles/profile/profile_widget.cpp b/Telegram/SourceFiles/profile/profile_widget.cpp new file mode 100644 index 0000000000..5f7b1c7b69 --- /dev/null +++ b/Telegram/SourceFiles/profile/profile_widget.cpp @@ -0,0 +1,119 @@ +/* +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 "profile/profile_widget.h" + +#include "profile/profile_inner_widget.h" +#include "mainwindow.h" +#include "application.h" + +namespace Profile { + +Widget::Widget(QWidget *parent, PeerData *peer) : TWidget(parent) +, _scroll(this, st::setScroll) +, _inner(this, peer) +, _sideShadow(this, st::shadowColor) { + _scroll->setWidget(_inner); + _scroll->move(0, 0); + _scroll->show(); + + _sideShadow->setVisible(!Adaptive::OneColumn()); + + connect(_scroll, SIGNAL(scrolled()), _inner, SLOT(updateSelected())); + connect(_scroll, SIGNAL(scrolled()), this, SLOT(onScroll())); +} + +PeerData *Widget::peer() const { + return _inner->peer(); +} + +void Widget::setGeometryWithTopMoved(const QRect &newGeometry, int topDelta) { + _topDelta = topDelta; + bool willBeResized = (size() != newGeometry.size()); + if (geometry() != newGeometry) { + setGeometry(newGeometry); + } + if (!willBeResized) { + resizeEvent(nullptr); + } + _topDelta = 0; +} + +void Widget::showAnimated(SlideDirection direction, const QPixmap &oldContentCache) { + show(); + _scroll->show(); + _sideShadow->hide(); + auto myContentCache = myGrab(this); + _scroll->hide(); + _sideShadow->show(); + + _showAnimation = std_::make_unique(); + _showAnimation->setDirection(direction); + _showAnimation->setRepaintCallback(func(this, &Widget::repaintCallback)); + _showAnimation->setFinishedCallback(func(this, &Widget::showFinished)); + _showAnimation->setPixmaps(oldContentCache, myContentCache); + _showAnimation->start(); +} + +void Widget::setInnerFocus() { + _inner->setFocus(); +} + +void Widget::resizeEvent(QResizeEvent *e) { + int newScrollTop = _scroll->scrollTop() + _topDelta; + if (_scroll->size() != size()) { + _scroll->resize(size()); + if (_inner->width() != width()) { + _inner->resizeToWidth(width(), _scroll->height()); + } + } + if (!_scroll->isHidden()) { + if (_topDelta) { + _scroll->scrollToY(newScrollTop); + } + int notDisplayedAtBottom = _scroll->scrollTopMax() - _scroll->scrollTop(); + if (notDisplayedAtBottom > 0) { + _inner->decreaseAdditionalHeight(notDisplayedAtBottom); + } + } + + _sideShadow->resize(st::lineWidth, height()); + _sideShadow->moveToLeft(0, 0); +} + +void Widget::paintEvent(QPaintEvent *e) { + if (Ui::skipPaintEvent(this, e)) return; + + if (_showAnimation) { + Painter p(this); + _showAnimation->paintContents(p, e->rect()); + } +} + +void Widget::showFinished() { + if (isHidden()) return; + + App::app()->mtpUnpause(); + _scroll->show(); + setInnerFocus(); +} + +} // namespace Profile diff --git a/Telegram/SourceFiles/profile/profile_widget.h b/Telegram/SourceFiles/profile/profile_widget.h new file mode 100644 index 0000000000..13e765edc7 --- /dev/null +++ b/Telegram/SourceFiles/profile/profile_widget.h @@ -0,0 +1,69 @@ +/* +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/slide_animation.h" + +class ScrollArea; + +namespace Profile { + +class InnerWidget; +class Widget final : public TWidget { + Q_OBJECT + +public: + Widget(QWidget *parent, PeerData *peer); + + PeerData *peer() const; + + // When resizing the widget with top edge moved up or down and we + // want to add this top movement to the scroll position, so inner + // content will not move. + void setGeometryWithTopMoved(const QRect &newGeometry, int topDelta); + + void showAnimated(SlideDirection direction, const QPixmap &oldContentCache); + + void setInnerFocus(); + +protected: + void resizeEvent(QResizeEvent *e) override; + void paintEvent(QPaintEvent *e) override; + +private: + // QWidget::update() method is overloaded and we need template deduction. + void repaintCallback() { + update(); + } + void showFinished(); + + ChildWidget _scroll; + ChildWidget _inner; + ChildWidget _sideShadow; + + std_::unique_ptr _showAnimation; + + // Saving here topDelta in resizeWithTopMoved() to get it passed to resizeEvent(). + int _topDelta = 0; + +}; + +} // namespace Profile diff --git a/Telegram/SourceFiles/profilewidget.cpp b/Telegram/SourceFiles/profilewidget.cpp index a5ad1cc3a7..9dee29e7a0 100644 --- a/Telegram/SourceFiles/profilewidget.cpp +++ b/Telegram/SourceFiles/profilewidget.cpp @@ -33,9 +33,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "apiwrap.h" #include "window/top_bar_widget.h" -ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, PeerData *peer) : TWidget(0) +ProfileInner::ProfileInner(ProfileWidget *profile, PeerData *peer) : TWidget(0) , _profile(profile) -, _scroll(scroll) , _peer(peer->migrateTo() ? peer->migrateTo() : peer) , _peerUser(_peer->asUser()) , _peerChat(_peer->asChat()) @@ -145,7 +144,7 @@ ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, PeerData } // profile - _nameText.setText(st::profileNameFont, _nameCache, _textNameOptions); +// _nameText.setText(st::profileNameFont, _nameCache, _textNameOptions); connect(&_uploadPhoto, SIGNAL(clicked()), this, SLOT(onUpdatePhoto())); connect(&_addParticipant, SIGNAL(clicked()), this, SLOT(onAddParticipant())); connect(&_sendMessage, SIGNAL(clicked()), this, SLOT(onSendMessage())); @@ -636,7 +635,7 @@ void ProfileInner::peerUpdated(PeerData *data) { } if (_peer->name != _nameCache) { _nameCache = _peer->name; - _nameText.setText(st::profileNameFont, _nameCache, _textNameOptions); +// _nameText.setText(st::profileNameFont, _nameCache, _textNameOptions); } } if (!_updateDelayed) { @@ -838,7 +837,7 @@ void ProfileInner::paintEvent(QPaintEvent *e) { // profile top += st::profilePadding.top(); if (_photoLink || _peerUser || (_peerChat && !_peerChat->canEdit()) || (_peerChannel && !_amCreator)) { - _peer->paintUserpic(p, st::profilePhotoSize, _left, top); +// _peer->paintUserpic(p, st::profilePhotoSize, _left, top); } else { if (a_photoOver.current() < 1) { p.drawSprite(QPoint(_left, top), st::setPhotoImg); @@ -850,44 +849,44 @@ void ProfileInner::paintEvent(QPaintEvent *e) { } } - int32 namew = _width - st::profilePhotoSize - st::profileNameLeft; +// int32 namew = _width - st::profilePhotoSize - st::profileNameLeft; p.setPen(st::black->p); if (_peer->isVerified()) { - namew -= st::verifiedCheckProfile.pxWidth() + st::verifiedCheckProfilePos.x(); - int32 cx = _left + st::profilePhotoSize + st::profileNameLeft + qMin(_nameText.maxWidth(), namew); - p.drawSprite(QPoint(cx, top + st::profileNameTop) + st::verifiedCheckProfilePos, st::verifiedCheckProfile); + //namew -= st::verifiedCheckProfile.pxWidth() + st::verifiedCheckProfilePos.x(); + //int32 cx = _left + st::profilePhotoSize + st::profileNameLeft + qMin(_nameText.maxWidth(), namew); + //p.drawSprite(QPoint(cx, top + st::profileNameTop) + st::verifiedCheckProfilePos, st::verifiedCheckProfile); } - _nameText.drawElided(p, _left + st::profilePhotoSize + st::profileNameLeft, top + st::profileNameTop, namew); +// _nameText.drawElided(p, _left + st::profilePhotoSize + st::profileNameLeft, top + st::profileNameTop, namew); - p.setFont(st::profileStatusFont->f); + //p.setFont(st::profileStatusFont->f); int32 addbyname = 0; if (_peerUser && !_peerUser->username.isEmpty()) { - addbyname = st::profileStatusTop + st::linkFont->ascent - (st::profileNameTop + st::profileNameFont->ascent); - p.setPen(st::black->p); - p.drawText(_left + st::profilePhotoSize + st::profileStatusLeft, top + st::profileStatusTop + st::linkFont->ascent, '@' + _peerUser->username); + //addbyname = st::profileStatusTop + st::linkFont->ascent - (st::profileNameTop + st::profileNameFont->ascent); + //p.setPen(st::black->p); + //p.drawText(_left + st::profilePhotoSize + st::profileStatusLeft, top + st::profileStatusTop + st::linkFont->ascent, '@' + _peerUser->username); } else if (_peerChannel && (_peerChannel->isPublic() || _peerChannel->canEditUsername())) { - addbyname = st::profileStatusTop + st::linkFont->ascent - (st::profileNameTop + st::profileNameFont->ascent); +// addbyname = st::profileStatusTop + st::linkFont->ascent - (st::profileNameTop + st::profileNameFont->ascent); } if (!_peerChannel || !_peerChannel->canViewParticipants() || _peerChannel->isMegagroup()) { - p.setPen((_peerUser && App::onlineColorUse(_peerUser, l_time) ? st::profileOnlineColor : st::profileOfflineColor)->p); - p.drawText(_left + st::profilePhotoSize + st::profileStatusLeft, top + addbyname + st::profileStatusTop + st::linkFont->ascent, _onlineText); + //p.setPen((_peerUser && App::onlineColorUse(_peerUser, l_time) ? st::profileOnlineColor : st::profileOfflineColor)->p); + //p.drawText(_left + st::profilePhotoSize + st::profileStatusLeft, top + addbyname + st::profileStatusTop + st::linkFont->ascent, _onlineText); } if (!_cancelPhoto.isHidden()) { - p.setPen(st::profileOfflineColor->p); - p.drawText(_left + st::profilePhotoSize + st::profilePhoneLeft, _cancelPhoto.y() + st::linkFont->ascent, lang(lng_settings_uploading_photo)); + //p.setPen(st::profileOfflineColor->p); + //p.drawText(_left + st::profilePhotoSize + st::profilePhoneLeft, _cancelPhoto.y() + st::linkFont->ascent, lang(lng_settings_uploading_photo)); } if (!_errorText.isEmpty()) { p.setFont(st::setErrFont->f); p.setPen(st::setErrColor->p); - p.drawText(_left + st::profilePhotoSize + st::profilePhoneLeft, _cancelPhoto.y() + st::profilePhoneFont->ascent, _errorText); +// p.drawText(_left + st::profilePhotoSize + st::profilePhoneLeft, _cancelPhoto.y() + st::profilePhoneFont->ascent, _errorText); } if (!_phoneText.isEmpty()) { p.setPen(st::black->p); p.setFont(st::linkFont->f); - p.drawText(_left + st::profilePhotoSize + st::profilePhoneLeft, top + addbyname + st::profilePhoneTop + st::profilePhoneFont->ascent, _phoneText); +// p.drawText(_left + st::profilePhotoSize + st::profilePhoneLeft, top + addbyname + st::profilePhoneTop + st::profilePhoneFont->ascent, _phoneText); } - top += st::profilePhotoSize; +// top += st::profilePhotoSize; top += st::profileButtonTop; if ((!_peerChat || _peerChat->canEdit()) && (!_peerChannel || _amCreator || (_peerChannel->canAddParticipants() && _peerChannel->isMegagroup()))) { @@ -1385,24 +1384,24 @@ void ProfileInner::resizeEvent(QResizeEvent *e) { top += st::profilePadding.top(); int32 addbyname = 0; if (_peerChannel && (_peerChannel->isPublic() || _peerChannel->canEditUsername())) { - _username.move(_left + st::profilePhotoSize + st::profileStatusLeft, top + st::profileStatusTop); - addbyname = st::profileStatusTop + st::linkFont->ascent - (st::profileNameTop + st::profileNameFont->ascent); + //_username.move(_left + st::profilePhotoSize + st::profileStatusLeft, top + st::profileStatusTop); + //addbyname = st::profileStatusTop + st::linkFont->ascent - (st::profileNameTop + st::profileNameFont->ascent); } - _members.move(_left + st::profilePhotoSize + st::profileStatusLeft, top + addbyname + st::profileStatusTop); - addbyname += st::profileStatusTop + st::linkFont->ascent - (st::profileNameTop + st::profileNameFont->ascent); + //_members.move(_left + st::profilePhotoSize + st::profileStatusLeft, top + addbyname + st::profileStatusTop); + //addbyname += st::profileStatusTop + st::linkFont->ascent - (st::profileNameTop + st::profileNameFont->ascent); if (!_admins.isHidden()) { - _admins.move(_left + st::profilePhotoSize + st::profileStatusLeft, top + addbyname + st::profileStatusTop); - addbyname += st::profileStatusTop + st::linkFont->ascent - (st::profileNameTop + st::profileNameFont->ascent); + //_admins.move(_left + st::profilePhotoSize + st::profileStatusLeft, top + addbyname + st::profileStatusTop); + //addbyname += st::profileStatusTop + st::linkFont->ascent - (st::profileNameTop + st::profileNameFont->ascent); } if ((_peerChat && _amCreator && _peerChat->canEdit()) || (_peerChannel && (_amCreator || _peerChannel->amEditor() || _peerChannel->amModerator()))) { - _cancelPhoto.move(_left + _width - _cancelPhoto.width(), top + st::profilePhotoSize - st::linkFont->height); +// _cancelPhoto.move(_left + _width - _cancelPhoto.width(), top + st::profilePhotoSize - st::linkFont->height); } else { _cancelPhoto.move(_left + _width - _cancelPhoto.width(), top + st::profilePhoneTop); - _botSettings.move(_left + st::profilePhotoSize + st::profilePhoneLeft, top + st::profileStatusTop + st::linkFont->ascent - (st::profileNameTop + st::profileNameFont->ascent) + st::profilePhoneTop); + // _botSettings.move(_left + st::profilePhotoSize + st::profilePhoneLeft, top + st::profileStatusTop + st::linkFont->ascent - (st::profileNameTop + st::profileNameFont->ascent) + st::profilePhoneTop); _botHelp.move(_botSettings.x() + (_botSettings.isHidden() ? 0 : _botSettings.width() + st::profilePhoneLeft), _botSettings.y()); } - _pinnedMessage.move(_left + st::profilePhotoSize + st::profileStatusLeft, top + addbyname + st::profileStatusTop); - top += st::profilePhotoSize; + //_pinnedMessage.move(_left + st::profilePhotoSize + st::profileStatusLeft, top + addbyname + st::profileStatusTop); + //top += st::profilePhotoSize; top += st::profileButtonTop; @@ -1514,22 +1513,22 @@ void ProfileInner::contextMenuEvent(QContextMenuEvent *e) { _menu = 0; } if (!_phoneText.isEmpty() || _peerUser) { - QRect info(_left + st::profilePhotoSize + st::profilePhoneLeft, st::profilePadding.top(), _width - st::profilePhotoSize - st::profilePhoneLeft, st::profilePhotoSize); - if (info.contains(mapFromGlobal(e->globalPos()))) { - _menu = new PopupMenu(); - if (_peerUser) { - _menu->addAction(lang(lng_profile_copy_fullname), this, SLOT(onCopyFullName()))->setEnabled(true); - } - if (!_phoneText.isEmpty()) { - _menu->addAction(lang(lng_profile_copy_phone), this, SLOT(onCopyPhone()))->setEnabled(true); - } - if (_peerUser && !_peerUser->username.isEmpty()) { - _menu->addAction(lang(lng_context_copy_mention), this, SLOT(onCopyUsername()))->setEnabled(true); - } - connect(_menu, SIGNAL(destroyed(QObject*)), this, SLOT(onMenuDestroy(QObject*))); - _menu->popup(e->globalPos()); - e->accept(); - } +// QRect info(_left + st::profilePhotoSize + st::profilePhoneLeft, st::profilePadding.top(), _width - st::profilePhotoSize - st::profilePhoneLeft, st::profilePhotoSize); + //if (info.contains(mapFromGlobal(e->globalPos()))) { + // _menu = new PopupMenu(); + // if (_peerUser) { + // _menu->addAction(lang(lng_profile_copy_fullname), this, SLOT(onCopyFullName()))->setEnabled(true); + // } + // if (!_phoneText.isEmpty()) { + // _menu->addAction(lang(lng_profile_copy_phone), this, SLOT(onCopyPhone()))->setEnabled(true); + // } + // if (_peerUser && !_peerUser->username.isEmpty()) { + // _menu->addAction(lang(lng_context_copy_mention), this, SLOT(onCopyUsername()))->setEnabled(true); + // } + // connect(_menu, SIGNAL(destroyed(QObject*)), this, SLOT(onMenuDestroy(QObject*))); + // _menu->popup(e->globalPos()); + // e->accept(); + //} } } @@ -1863,7 +1862,7 @@ QString ProfileInner::overviewLinkText(int32 type, int32 count) { ProfileWidget::ProfileWidget(QWidget *parent, PeerData *peer) : TWidget(parent) , _scroll(this, st::setScroll) -, _inner(this, &_scroll, peer) +, _inner(this, peer) , _a_show(animation(this, &ProfileWidget::step_show)) , _sideShadow(this, st::shadowColor) , _topShadow(this, st::shadowColor) diff --git a/Telegram/SourceFiles/profilewidget.h b/Telegram/SourceFiles/profilewidget.h index a98b097078..6a8e1debd2 100644 --- a/Telegram/SourceFiles/profilewidget.h +++ b/Telegram/SourceFiles/profilewidget.h @@ -26,7 +26,7 @@ class ProfileInner : public TWidget, public RPCSender, public ClickHandlerHost { public: - ProfileInner(ProfileWidget *profile, ScrollArea *scroll, PeerData *peer); + ProfileInner(ProfileWidget *profile, PeerData *peer); void start(); @@ -147,7 +147,6 @@ private: bool migrateFail(const RPCError &error); ProfileWidget *_profile; - ScrollArea *_scroll; PeerData *_peer; UserData *_peerUser; diff --git a/Telegram/SourceFiles/ui/animation.cpp b/Telegram/SourceFiles/ui/animation.cpp index a9ce8f9109..03b194fe9f 100644 --- a/Telegram/SourceFiles/ui/animation.cpp +++ b/Telegram/SourceFiles/ui/animation.cpp @@ -115,7 +115,7 @@ namespace anim { void Animation::start() { if (!_manager) return; - _cb.start(); + _callbacks.start(); _manager->start(this); _animating = true; } @@ -237,8 +237,8 @@ QPixmap _prepareFrame(const ClipFrameRequest &request, const QImage &original, b return QPixmap::fromImage(original, Qt::ColorOnly); } -ClipReader::ClipReader(const FileLocation &location, const QByteArray &data, Callback::Creator cb) -: _cb(cb) +ClipReader::ClipReader(const FileLocation &location, const QByteArray &data, Callback &&callback) +: _callback(std_::move(callback)) , _state(ClipReading) , _width(0) , _height(0) @@ -334,7 +334,7 @@ void ClipReader::moveToNextWrite() const { void ClipReader::callback(ClipReader *reader, int32 threadIndex, ClipReaderNotification notification) { // check if reader is not deleted already if (_clipManagers.size() > threadIndex && _clipManagers.at(threadIndex)->carries(reader)) { - reader->_cb.call(notification); + reader->_callback.call(notification); } } diff --git a/Telegram/SourceFiles/ui/animation.h b/Telegram/SourceFiles/ui/animation.h index 68ccb92360..d7c3e4a143 100644 --- a/Telegram/SourceFiles/ui/animation.h +++ b/Telegram/SourceFiles/ui/animation.h @@ -203,39 +203,42 @@ public: virtual void start() {} virtual void step(Animation *a, uint64 ms, bool timer) = 0; virtual ~AnimationImplementation() {} + }; -class AnimationCreator { -public: - AnimationCreator(AnimationImplementation *ptr) : _ptr(ptr) {} - AnimationCreator(const AnimationCreator &other) : _ptr(other.create()) {} - AnimationImplementation *create() const { return getPointerAndReset(_ptr); } - ~AnimationCreator() { deleteAndMark(_ptr); } -private: - AnimationCreator &operator=(const AnimationCreator &other) = delete; - mutable AnimationImplementation *_ptr; -}; + class AnimationCallbacks { public: - AnimationCallbacks(const AnimationCreator &creator) : _implementation(creator.create()) {} + AnimationCallbacks(AnimationImplementation *implementation) : _implementation(implementation) {} + AnimationCallbacks(const AnimationCallbacks &other) = delete; + AnimationCallbacks &operator=(const AnimationCallbacks &other) = delete; + AnimationCallbacks(AnimationCallbacks &&other) : _implementation(other._implementation) { + other._implementation = nullptr; + } + AnimationCallbacks &operator=(AnimationCallbacks &&other) { + std::swap(_implementation, other._implementation); + } + void start() { _implementation->start(); } void step(Animation *a, uint64 ms, bool timer) { _implementation->step(a, ms, timer); } ~AnimationCallbacks() { deleteAndMark(_implementation); } + private: - AnimationCallbacks(const AnimationCallbacks &other); - AnimationCallbacks &operator=(const AnimationCallbacks &other) = delete; AnimationImplementation *_implementation; + }; class Animation { public: - Animation(AnimationCreator cb) : _cb(cb), _animating(false) { + Animation(AnimationCallbacks &&callbacks) + : _callbacks(std_::move(callbacks)) + , _animating(false) { } void start(); void stop(); void step(uint64 ms, bool timer = false) { - _cb.step(this, ms, timer); + _callbacks.step(this, ms, timer); } void step() { @@ -251,7 +254,7 @@ public: } private: - AnimationCallbacks _cb; + AnimationCallbacks _callbacks; bool _animating; }; @@ -279,8 +282,8 @@ private: }; template -AnimationCreator animation(Type *obj, typename AnimationCallbacksRelative::Method method) { - return AnimationCreator(new AnimationCallbacksRelative(obj, method)); +AnimationCallbacks animation(Type *obj, typename AnimationCallbacksRelative::Method method) { + return AnimationCallbacks(new AnimationCallbacksRelative(obj, method)); } template @@ -301,8 +304,8 @@ private: }; template -AnimationCreator animation(Type *obj, typename AnimationCallbacksAbsolute::Method method) { - return AnimationCreator(new AnimationCallbacksAbsolute(obj, method)); +AnimationCallbacks animation(Type *obj, typename AnimationCallbacksAbsolute::Method method) { + return AnimationCallbacks(new AnimationCallbacksAbsolute(obj, method)); } template @@ -329,8 +332,8 @@ private: }; template -AnimationCreator animation(Param param, Type *obj, typename AnimationCallbacksRelativeWithParam::Method method) { - return AnimationCreator(new AnimationCallbacksRelativeWithParam(param, obj, method)); +AnimationCallbacks animation(Param param, Type *obj, typename AnimationCallbacksRelativeWithParam::Method method) { + return AnimationCallbacks(new AnimationCallbacksRelativeWithParam(param, obj, method)); } template @@ -352,15 +355,15 @@ private: }; template -AnimationCreator animation(Param param, Type *obj, typename AnimationCallbacksAbsoluteWithParam::Method method) { - return AnimationCreator(new AnimationCallbacksAbsoluteWithParam(param, obj, method)); +AnimationCallbacks animation(Param param, Type *obj, typename AnimationCallbacksAbsoluteWithParam::Method method) { + return AnimationCallbacks(new AnimationCallbacksAbsoluteWithParam(param, obj, method)); } template class SimpleAnimation { public: - typedef Function Callback; + using Callback = Function; SimpleAnimation() : _data(0) { } @@ -385,9 +388,9 @@ public: return animating(ms) ? current() : def; } - void setup(const typename AnimType::Type &from, Callback::Creator update) { + void setup(const typename AnimType::Type &from, Callback &&update) { if (!_data) { - _data = new Data(from, update, animation(this, &SimpleAnimation::step)); + _data = new Data(from, std_::move(update), animation(this, &SimpleAnimation::step)); } else { _data->a = AnimType(from, from); } @@ -407,11 +410,11 @@ public: } private: - typedef struct _Data { - _Data(const typename AnimType::Type &from, Callback::Creator update, AnimationCreator acb) + struct Data { + Data(const typename AnimType::Type &from, Callback &&update, AnimationCallbacks &&acb) : a(from, from) - , _a(acb) - , update(update) + , _a(std_::move(acb)) + , update(std_::move(update)) , duration(0) , transition(anim::linear) { } @@ -420,7 +423,7 @@ private: Callback update; float64 duration; anim::transition transition; - } Data; + }; Data *_data; void step(float64 ms, bool timer) { @@ -506,9 +509,9 @@ class ClipReaderPrivate; class ClipReader { public: - typedef Function1 Callback; + using Callback = Function; - ClipReader(const FileLocation &location, const QByteArray &data, Callback::Creator cb); + ClipReader(const FileLocation &location, const QByteArray &data, Callback &&callback); static void callback(ClipReader *reader, int32 threadIndex, ClipReaderNotification notification); // reader can be deleted void setAutoplay() { @@ -555,7 +558,7 @@ public: private: - Callback _cb; + Callback _callback; ClipState _state; diff --git a/Telegram/SourceFiles/ui/flatbutton.cpp b/Telegram/SourceFiles/ui/flatbutton.cpp index ccf15f39ca..5462b395c8 100644 --- a/Telegram/SourceFiles/ui/flatbutton.cpp +++ b/Telegram/SourceFiles/ui/flatbutton.cpp @@ -335,7 +335,7 @@ void EmojiButton::paintEvent(QPaintEvent *e) { void EmojiButton::setLoading(bool loading) { if (_loading != loading) { - EnsureAnimation(a_loading, _loading ? 1. : 0., func(this, &EmojiButton::update)); + EnsureAnimation(a_loading, _loading ? 1. : 0., func(this, &EmojiButton::updateCallback)); a_loading.start(loading ? 1. : 0., st::emojiCircleDuration); _loading = loading; if (_loading) { diff --git a/Telegram/SourceFiles/ui/flatbutton.h b/Telegram/SourceFiles/ui/flatbutton.h index 4f6110843c..b02bae1406 100644 --- a/Telegram/SourceFiles/ui/flatbutton.h +++ b/Telegram/SourceFiles/ui/flatbutton.h @@ -151,9 +151,12 @@ private: void step_loading(uint64 ms, bool timer) { if (timer) { - update(); + updateCallback(); } } + void updateCallback() { + update(); + } }; diff --git a/Telegram/SourceFiles/ui/slide_animation.cpp b/Telegram/SourceFiles/ui/slide_animation.cpp new file mode 100644 index 0000000000..ecd59f1d88 --- /dev/null +++ b/Telegram/SourceFiles/ui/slide_animation.cpp @@ -0,0 +1,97 @@ +/* +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/slide_animation.h" + +SlideAnimation::SlideAnimation() +: _animation(animation(this, &SlideAnimation::step)) { +} + +void SlideAnimation::paintContents(Painter &p, const QRect &update) const { + _animation.step(getms()); + if (a_progress.current() < 1) { + p.fillRect(update, st::white); + int retina = cIntRetinaFactor(); + int underLeft = a_coordUnder.current(); + int underWidth = _cacheUnder.width() / retina; + int underHeight = _cacheUnder.height() / retina; + QRect underDest(0, 0, underWidth + underLeft, underHeight); + QRect underSrc(-underLeft * retina, 0, (underWidth + underLeft) * retina, underHeight * retina); + p.setOpacity(1. - a_progress.current()); + p.drawPixmap(underDest, _cacheUnder, underSrc); + p.setOpacity(a_progress.current()); + } + p.drawPixmap(a_coordOver.current(), 0, _cacheOver); +} + +void SlideAnimation::setDirection(SlideDirection direction) { + _direction = direction; +} + +void SlideAnimation::setPixmaps(const QPixmap &oldContentCache, const QPixmap &newContentCache) { + _cacheUnder = oldContentCache; + _cacheOver = newContentCache; +} + +void SlideAnimation::setRepaintCallback(RepaintCallback &&callback) { + _repaintCallback = std_::move(callback); +} + +void SlideAnimation::setFinishedCallback(FinishedCallback &&callback) { + _finishedCallback = std_::move(callback); +} + +void SlideAnimation::start() { + int width = _cacheUnder.width() / cIntRetinaFactor(); + int delta = qFloor(st::slideShift * width); + a_progress = anim::fvalue(0, 1); + if (_direction == SlideDirection::FromLeft) { + std::swap(_cacheUnder, _cacheOver); + a_coordUnder = anim::ivalue(-delta, 0); + a_coordOver = anim::ivalue(0, delta); + } else { + a_coordUnder = anim::ivalue(0, -delta); + a_coordOver = anim::ivalue(delta, 0); + } + _animation.start(); +} + +void SlideAnimation::step(float64 ms, bool timer) { + float64 dt = ms / st::slideDuration; + if (dt >= 1) { + dt = 1; + if (timer) { + _animation.stop(); + a_coordUnder.finish(); + a_coordOver.finish(); + + _finishedCallback.call(); + return; + } + } + + a_coordUnder.update(dt, anim::linear); + a_coordOver.update(dt, anim::linear); + a_progress.update(dt, anim::linear); + if (timer) { + _repaintCallback.call(); + } +} diff --git a/Telegram/SourceFiles/ui/slide_animation.h b/Telegram/SourceFiles/ui/slide_animation.h new file mode 100644 index 0000000000..0739cb0814 --- /dev/null +++ b/Telegram/SourceFiles/ui/slide_animation.h @@ -0,0 +1,58 @@ +/* +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 + +enum class SlideDirection { + FromRight, + FromLeft, +}; + +class SlideAnimation { +public: + SlideAnimation(); + + void paintContents(Painter &p, const QRect &update) const; + + void setDirection(SlideDirection direction); + void setPixmaps(const QPixmap &oldContentCache, const QPixmap &newContentCache); + + using RepaintCallback = Function; + void setRepaintCallback(RepaintCallback &&callback); + + using FinishedCallback = Function; + void setFinishedCallback(FinishedCallback &&callback); + + void start(); + +private: + void step(float64 ms, bool timer); + + SlideDirection _direction = SlideDirection::FromRight; + + mutable Animation _animation; + QPixmap _cacheUnder, _cacheOver; + anim::ivalue a_coordUnder, a_coordOver; + anim::fvalue a_progress; + + RepaintCallback _repaintCallback; + FinishedCallback _finishedCallback; + +}; diff --git a/Telegram/Telegram.vcxproj b/Telegram/Telegram.vcxproj index cc6dc115fc..71e8ad6848 100644 --- a/Telegram/Telegram.vcxproj +++ b/Telegram/Telegram.vcxproj @@ -386,6 +386,18 @@ true true + + true + true + + + true + true + + + true + true + true true @@ -673,6 +685,18 @@ true true + + true + true + + + true + true + + + true + true + true true @@ -986,6 +1010,18 @@ true true + + true + true + + + true + true + + + true + true + true true @@ -1052,6 +1088,7 @@ + @@ -1125,6 +1162,9 @@ + + + true true @@ -1173,6 +1213,7 @@ + @@ -1257,6 +1298,7 @@ + @@ -1375,6 +1417,48 @@ "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl\Release\include" "-fstdafx.h" "-f../../SourceFiles/mtproto/session.h" + + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing profile_widget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/profile/profile_widget.h" -DAL_LIBTYPE_STATIC -DCUSTOM_API_ID -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl\Release\include" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing profile_widget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/profile/profile_widget.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl_debug\Debug\include" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing profile_widget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/profile/profile_widget.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl\Release\include" + + + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing profile_inner_widget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/profile/profile_inner_widget.h" -DAL_LIBTYPE_STATIC -DCUSTOM_API_ID -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl\Release\include" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing profile_inner_widget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/profile/profile_inner_widget.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl_debug\Debug\include" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing profile_inner_widget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/profile/profile_inner_widget.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl\Release\include" + + + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing profile_cover.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/profile/profile_cover.h" -DAL_LIBTYPE_STATIC -DCUSTOM_API_ID -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl\Release\include" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing profile_cover.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/profile/profile_cover.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl_debug\Debug\include" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing profile_cover.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/profile/profile_cover.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl\Release\include" + @@ -1537,6 +1621,7 @@ .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl\Release\include" "-fstdafx.h" "-f../../SourceFiles/ui/twidget.h" + @@ -2391,6 +2476,7 @@ + diff --git a/Telegram/Telegram.vcxproj.filters b/Telegram/Telegram.vcxproj.filters index 7cf860ae70..9abae748d3 100644 --- a/Telegram/Telegram.vcxproj.filters +++ b/Telegram/Telegram.vcxproj.filters @@ -91,6 +91,9 @@ {6b33ddc0-a7e2-4961-81dc-e1b5de2e2c60} + + {b761f2a4-0e8c-4e52-b179-7a3185c046c4} + @@ -1104,6 +1107,48 @@ SourceFiles\ui\style + + SourceFiles\profile + + + GeneratedFiles\Deploy + + + GeneratedFiles\Debug + + + GeneratedFiles\Release + + + SourceFiles\ui + + + GeneratedFiles\Deploy + + + GeneratedFiles\Debug + + + GeneratedFiles\Release + + + SourceFiles\profile + + + GeneratedFiles\styles + + + SourceFiles\profile + + + GeneratedFiles\Deploy + + + GeneratedFiles\Debug + + + GeneratedFiles\Release + @@ -1277,6 +1322,12 @@ Resources\winrc + + SourceFiles\ui + + + GeneratedFiles\styles + @@ -1516,6 +1567,15 @@ Resources\langs + + SourceFiles\profile + + + SourceFiles\profile + + + SourceFiles\profile + @@ -1585,6 +1645,9 @@ SourceFiles\overview + + SourceFiles\profile +