diff --git a/Telegram/Resources/basic.style b/Telegram/Resources/basic.style index a11084570..0724ccd9a 100644 --- a/Telegram/Resources/basic.style +++ b/Telegram/Resources/basic.style @@ -78,6 +78,8 @@ slideDuration: 240; slideShift: 100px; slideShadow: icon {{ "slide_shadow", slideFadeOutShadowFg }}; +slideWrapDuration: 150; + linkCropLimit: 360px; linkFont: normalFont; linkOverFont: font(fsize underline); diff --git a/Telegram/SourceFiles/base/lambda.h b/Telegram/SourceFiles/base/lambda.h index 48742ce75..6046bff58 100644 --- a/Telegram/SourceFiles/base/lambda.h +++ b/Telegram/SourceFiles/base/lambda.h @@ -365,9 +365,14 @@ public: } } - inline Return operator()(Args... args) { + template < + typename ...OtherArgs, + typename = std::enable_if_t<(sizeof...(Args) == sizeof...(OtherArgs))>> + inline Return operator()(OtherArgs&&... args) { Assert(data_.vtable != nullptr); - return data_.vtable->call(data_.storage, std::forward(args)...); + return data_.vtable->call( + data_.storage, + std::forward(args)...); } explicit operator bool() const { @@ -437,9 +442,14 @@ public: return *this; } - inline Return operator()(Args... args) const { + template < + typename ...OtherArgs, + typename = std::enable_if_t<(sizeof...(Args) == sizeof...(OtherArgs))>> + inline Return operator()(OtherArgs&&... args) const { Assert(this->data_.vtable != nullptr); - return this->data_.vtable->const_call(this->data_.storage, std::forward(args)...); + return this->data_.vtable->const_call( + this->data_.storage, + std::forward(args)...); } void swap(lambda &other) { diff --git a/Telegram/SourceFiles/base/observer.h b/Telegram/SourceFiles/base/observer.h index 24de58399..3b505e80c 100644 --- a/Telegram/SourceFiles/base/observer.h +++ b/Telegram/SourceFiles/base/observer.h @@ -22,6 +22,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include #include +#include #include "base/type_traits.h" namespace base { @@ -460,4 +461,31 @@ private: void HandleObservables(); +template < + typename Type, + typename = std::enable_if_t>> +inline rpl::producer ObservableViewer( + base::Observable &observable) { + return [&observable](const rpl::consumer &consumer) { + auto lifetime = rpl::lifetime(); + lifetime.make_state( + observable.add_subscription([consumer](auto &&update) { + consumer.put_next_copy(update); + })); + return lifetime; + }; +} + +inline rpl::producer<> ObservableViewer( + base::Observable &observable) { + return [&observable](const rpl::consumer<> &consumer) { + auto lifetime = rpl::lifetime(); + lifetime.make_state( + observable.add_subscription([consumer]() { + consumer.put_next({}); + })); + return lifetime; + }; +} + } // namespace base diff --git a/Telegram/SourceFiles/base/optional.h b/Telegram/SourceFiles/base/optional.h index bfb6ec8a0..c0d45c8d0 100644 --- a/Telegram/SourceFiles/base/optional.h +++ b/Telegram/SourceFiles/base/optional.h @@ -20,6 +20,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #pragma once +#include #include "base/variant.h" namespace base { diff --git a/Telegram/SourceFiles/boxes/abstract_box.h b/Telegram/SourceFiles/boxes/abstract_box.h index 90a3b2775..178629615 100644 --- a/Telegram/SourceFiles/boxes/abstract_box.h +++ b/Telegram/SourceFiles/boxes/abstract_box.h @@ -21,6 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #pragma once #include "layerwidget.h" +#include "ui/rp_widget.h" #include "ui/widgets/shadow.h" namespace Ui { @@ -58,7 +59,7 @@ public: }; -class BoxContent : public TWidget, protected base::Subscriber { +class BoxContent : public Ui::RpWidget, protected base::Subscriber { Q_OBJECT public: diff --git a/Telegram/SourceFiles/boxes/edit_privacy_box.cpp b/Telegram/SourceFiles/boxes/edit_privacy_box.cpp index 16f40322b..430c60e01 100644 --- a/Telegram/SourceFiles/boxes/edit_privacy_box.cpp +++ b/Telegram/SourceFiles/boxes/edit_privacy_box.cpp @@ -24,7 +24,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "ui/widgets/checkbox.h" #include "ui/widgets/labels.h" #include "ui/widgets/buttons.h" -#include "ui/effects/widget_slide_wrap.h" +#include "ui/wrap/slide_wrap.h" #include "boxes/peer_list_controllers.h" #include "apiwrap.h" #include "auth_session.h" @@ -252,7 +252,7 @@ std::vector> &EditPrivacyBox::exceptionUsers(Exception excep Unexpected("Invalid exception value."); } -object_ptr> &EditPrivacyBox::exceptionLink(Exception exception) { +object_ptr> &EditPrivacyBox::exceptionLink(Exception exception) { switch (exception) { case Exception::Always: return _alwaysLink; case Exception::Never: return _neverLink; @@ -284,9 +284,10 @@ void EditPrivacyBox::createWidgets() { widget.create(this, text, Ui::FlatLabel::InitType::Simple, st); }; auto createExceptionLink = [this](Exception exception) { - exceptionLink(exception).create(this, object_ptr(this, exceptionLinkText(exception)), exceptionLinkMargins(), [this] { - resizeGetHeight(width()); - }); + exceptionLink(exception).create(this, object_ptr(this, exceptionLinkText(exception)), exceptionLinkMargins()); + exceptionLink(exception)->heightValue() + | rpl::on_next([this](int) { resizeToWidth(width()); }) + | rpl::start(lifetime()); exceptionLink(exception)->entity()->setClickedCallback([this, exception] { editExceptionUsers(exception); }); }; diff --git a/Telegram/SourceFiles/boxes/edit_privacy_box.h b/Telegram/SourceFiles/boxes/edit_privacy_box.h index 46eaae29f..2760ba50a 100644 --- a/Telegram/SourceFiles/boxes/edit_privacy_box.h +++ b/Telegram/SourceFiles/boxes/edit_privacy_box.h @@ -31,7 +31,7 @@ class RadioenumGroup; template class Radioenum; template -class WidgetSlideWrap; +class SlideWrap; } // namespace Ui class EditPrivacyBox : public BoxContent, private MTP::Sender { @@ -103,7 +103,7 @@ private: void editExceptionUsers(Exception exception); QString exceptionLinkText(Exception exception); std::vector> &exceptionUsers(Exception exception); - object_ptr> &exceptionLink(Exception exception); + object_ptr> &exceptionLink(Exception exception); std::unique_ptr _controller; Option _option = Option::Everyone; @@ -116,8 +116,8 @@ private: object_ptr> _nobody = { nullptr }; object_ptr _warning = { nullptr }; object_ptr _exceptionsTitle = { nullptr }; - object_ptr> _alwaysLink = { nullptr }; - object_ptr> _neverLink = { nullptr }; + object_ptr> _alwaysLink = { nullptr }; + object_ptr> _neverLink = { nullptr }; object_ptr _exceptionsDescription = { nullptr }; std::vector> _alwaysUsers; diff --git a/Telegram/SourceFiles/boxes/notifications_box.cpp b/Telegram/SourceFiles/boxes/notifications_box.cpp index ed83a00bf..141daf59a 100644 --- a/Telegram/SourceFiles/boxes/notifications_box.cpp +++ b/Telegram/SourceFiles/boxes/notifications_box.cpp @@ -127,7 +127,9 @@ void NotificationsBox::prepare() { _sampleOpacities.push_back(Animation()); } _countSlider->setActiveSectionFast(_oldCount - 1); - _countSlider->setSectionActivatedCallback([this] { countChanged(); }); + _countSlider->sectionActivated() + | rpl::on_next([this](int) { countChanged(); }) + | rpl::start(lifetime()); setMouseTracking(true); diff --git a/Telegram/SourceFiles/boxes/peer_list_box.cpp b/Telegram/SourceFiles/boxes/peer_list_box.cpp index 11127b473..85ce75236 100644 --- a/Telegram/SourceFiles/boxes/peer_list_box.cpp +++ b/Telegram/SourceFiles/boxes/peer_list_box.cpp @@ -28,7 +28,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "ui/widgets/labels.h" #include "ui/effects/round_checkbox.h" #include "ui/effects/ripple_animation.h" -#include "ui/effects/widget_slide_wrap.h" +#include "ui/wrap/slide_wrap.h" #include "lang/lang_keys.h" #include "observer_peer.h" #include "storage/file_download.h" @@ -44,9 +44,10 @@ void PeerListBox::createMultiSelect() { Expects(_select == nullptr); auto entity = object_ptr(this, st::contactsMultiSelect, langFactory(lng_participant_filter)); - auto margins = style::margins(0, 0, 0, 0); - auto callback = [this] { updateScrollSkips(); }; - _select.create(this, std::move(entity), margins, std::move(callback)); + _select.create(this, std::move(entity)); + _select->heightValue() + | rpl::on_next([this](int) { updateScrollSkips(); }) + | rpl::start(lifetime()); _select->entity()->setSubmittedCallback([this](bool chtrlShiftEnter) { _inner->submitted(); }); _select->entity()->setQueryChangedCallback([this](const QString &query) { searchQueryChanged(query); }); _select->entity()->setItemRemovedCallback([this](uint64 itemId) { @@ -86,7 +87,7 @@ void PeerListBox::prepare() { setDimensions(st::boxWideWidth, st::boxMaxListHeight); if (_select) { - _select->finishAnimation(); + _select->finishAnimations(); _scrollBottomFixed = true; onScrollToY(0); } @@ -1158,7 +1159,9 @@ void PeerListBox::Inner::submitted() { } } -void PeerListBox::Inner::setVisibleTopBottom(int visibleTop, int visibleBottom) { +void PeerListBox::Inner::visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) { _visibleTop = visibleTop; _visibleBottom = visibleBottom; loadProfilePhotos(); diff --git a/Telegram/SourceFiles/boxes/peer_list_box.h b/Telegram/SourceFiles/boxes/peer_list_box.h index 394ba0088..073316318 100644 --- a/Telegram/SourceFiles/boxes/peer_list_box.h +++ b/Telegram/SourceFiles/boxes/peer_list_box.h @@ -29,7 +29,7 @@ class RippleAnimation; class RoundImageCheckbox; class MultiSelect; template -class WidgetSlideWrap; +class SlideWrap; class FlatLabel; } // namespace Ui @@ -378,7 +378,7 @@ private: void updateScrollSkips(); void searchQueryChanged(const QString &query); - object_ptr> _select = { nullptr }; + object_ptr> _select = { nullptr }; class Inner; QPointer _inner; @@ -401,8 +401,6 @@ public: void clearSelection(); - void setVisibleTopBottom(int visibleTop, int visibleBottom) override; - void searchQueryChanged(QString query); void submitted(); @@ -441,10 +439,11 @@ public: signals: void mustScrollTo(int ymin, int ymax); -public slots: - protected: int resizeGetHeight(int newWidth) override; + void visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) override; void paintEvent(QPaintEvent *e) override; void enterEventHook(QEvent *e) override; diff --git a/Telegram/SourceFiles/boxes/share_box.cpp b/Telegram/SourceFiles/boxes/share_box.cpp index 0936070e5..99e8beeb0 100644 --- a/Telegram/SourceFiles/boxes/share_box.cpp +++ b/Telegram/SourceFiles/boxes/share_box.cpp @@ -311,7 +311,9 @@ void ShareBox::Inner::invalidateCache() { } } -void ShareBox::Inner::setVisibleTopBottom(int visibleTop, int visibleBottom) { +void ShareBox::Inner::visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) { loadProfilePhotos(visibleTop); } diff --git a/Telegram/SourceFiles/boxes/share_box.h b/Telegram/SourceFiles/boxes/share_box.h index b4861b279..ba0183d60 100644 --- a/Telegram/SourceFiles/boxes/share_box.h +++ b/Telegram/SourceFiles/boxes/share_box.h @@ -125,7 +125,6 @@ public: void activateSkipRow(int direction); void activateSkipColumn(int direction); void activateSkipPage(int pageHeight, int direction); - void setVisibleTopBottom(int visibleTop, int visibleBottom) override; void updateFilter(QString filter = QString()); ~Inner(); @@ -138,6 +137,10 @@ signals: void searchByUsername(); protected: + void visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) override; + void paintEvent(QPaintEvent *e) override; void enterEventHook(QEvent *e) override; void leaveEventHook(QEvent *e) override; diff --git a/Telegram/SourceFiles/boxes/sticker_set_box.cpp b/Telegram/SourceFiles/boxes/sticker_set_box.cpp index 087f8a5d0..82866d594 100644 --- a/Telegram/SourceFiles/boxes/sticker_set_box.cpp +++ b/Telegram/SourceFiles/boxes/sticker_set_box.cpp @@ -401,11 +401,6 @@ void StickerSetBox::Inner::paintEvent(QPaintEvent *e) { } } -void StickerSetBox::Inner::setVisibleTopBottom(int visibleTop, int visibleBottom) { - _visibleTop = visibleTop; - _visibleBottom = visibleBottom; -} - bool StickerSetBox::Inner::loaded() const { return _loaded && !_pack.isEmpty(); } diff --git a/Telegram/SourceFiles/boxes/sticker_set_box.h b/Telegram/SourceFiles/boxes/sticker_set_box.h index 064f5abab..979daa55a 100644 --- a/Telegram/SourceFiles/boxes/sticker_set_box.h +++ b/Telegram/SourceFiles/boxes/sticker_set_box.h @@ -73,7 +73,6 @@ public: base::lambda title() const; QString shortName() const; - void setVisibleTopBottom(int visibleTop, int visibleBottom) override; void install(); ~Inner(); @@ -119,8 +118,6 @@ private: int32 _setHash = 0; MTPDstickerSet::Flags _setFlags = 0; - int _visibleTop = 0; - int _visibleBottom = 0; MTPInputStickerSet _input; mtpRequestId _installRequest = 0; diff --git a/Telegram/SourceFiles/boxes/stickers_box.cpp b/Telegram/SourceFiles/boxes/stickers_box.cpp index 98779482a..e3e4262c8 100644 --- a/Telegram/SourceFiles/boxes/stickers_box.cpp +++ b/Telegram/SourceFiles/boxes/stickers_box.cpp @@ -243,9 +243,9 @@ void StickersBox::prepare() { preloadArchivedSets(); } setNoContentMargin(true); - _tabs->setSectionActivatedCallback([this] { - switchTab(); - }); + _tabs->sectionActivated() + | rpl::on_next([this](int) { switchTab(); }) + | rpl::start(lifetime()); refreshTabs(); } if (_installed.widget() && _section != Section::Installed) _installed.widget()->hide(); @@ -1532,7 +1532,9 @@ void StickersBox::Inner::setRemovedSets(const Stickers::Order &removed) { } } -void StickersBox::Inner::setVisibleTopBottom(int visibleTop, int visibleBottom) { +void StickersBox::Inner::visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) { _visibleTop = visibleTop; _visibleBottom = visibleBottom; updateScrollbarWidth(); diff --git a/Telegram/SourceFiles/boxes/stickers_box.h b/Telegram/SourceFiles/boxes/stickers_box.h index 9323eeb90..010517303 100644 --- a/Telegram/SourceFiles/boxes/stickers_box.h +++ b/Telegram/SourceFiles/boxes/stickers_box.h @@ -173,7 +173,6 @@ public: _loadMoreCallback = std::move(callback); } - void setVisibleTopBottom(int visibleTop, int visibleBottom) override; void setMinHeight(int newWidth, int minHeight); int getVisibleTop() const { @@ -183,6 +182,10 @@ public: ~Inner(); protected: + void visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) override; + void paintEvent(QPaintEvent *e) override; void resizeEvent(QResizeEvent *e) override; void mousePressEvent(QMouseEvent *e) override; diff --git a/Telegram/SourceFiles/calls/calls_top_bar.cpp b/Telegram/SourceFiles/calls/calls_top_bar.cpp index 416698820..1e06faf44 100644 --- a/Telegram/SourceFiles/calls/calls_top_bar.cpp +++ b/Telegram/SourceFiles/calls/calls_top_bar.cpp @@ -75,7 +75,10 @@ void DebugInfoBox::updateText() { } // namespace -TopBar::TopBar(QWidget *parent, const base::weak_unique_ptr &call) : TWidget(parent) +TopBar::TopBar( + QWidget *parent, + const base::weak_unique_ptr &call) +: RpWidget(parent) , _call(call) , _durationLabel(this, st::callBarLabel) , _fullInfoLabel(this, st::callBarInfoLabel) diff --git a/Telegram/SourceFiles/calls/calls_top_bar.h b/Telegram/SourceFiles/calls/calls_top_bar.h index 67d3e395b..11b6fe7bc 100644 --- a/Telegram/SourceFiles/calls/calls_top_bar.h +++ b/Telegram/SourceFiles/calls/calls_top_bar.h @@ -22,6 +22,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "base/weak_unique_ptr.h" #include "base/timer.h" +#include "ui/rp_widget.h" namespace Ui { class IconButton; @@ -34,7 +35,7 @@ namespace Calls { class Call; -class TopBar : public TWidget, private base::Subscriber { +class TopBar : public Ui::RpWidget, private base::Subscriber { public: TopBar(QWidget *parent, const base::weak_unique_ptr &call); diff --git a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp index 1c41a9cb3..fe04b1fba 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp @@ -323,8 +323,10 @@ EmojiListWidget::EmojiListWidget(QWidget *parent, not_null connect(_picker, SIGNAL(hidden()), this, SLOT(onPickerHidden())); } -void EmojiListWidget::setVisibleTopBottom(int visibleTop, int visibleBottom) { - Inner::setVisibleTopBottom(visibleTop, visibleBottom); +void EmojiListWidget::visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) { + Inner::visibleTopBottomUpdated(visibleTop, visibleBottom); if (_footer) { _footer->setCurrentSectionIcon(currentSection(visibleTop)); } diff --git a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h index 42dcd7843..a698e26e9 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h +++ b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h @@ -92,7 +92,6 @@ public: using Section = Ui::Emoji::Section; - void setVisibleTopBottom(int visibleTop, int visibleBottom) override; void refreshRecent() override; void clearSelection() override; object_ptr createFooter() override; @@ -112,6 +111,10 @@ signals: void switchToStickers(); protected: + void visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) override; + void mousePressEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; @@ -136,6 +139,7 @@ private: int rowsTop = 0; int rowsBottom = 0; }; + template bool enumerateSections(Callback callback) const; SectionInfo sectionInfo(int section) const; diff --git a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp index 64a5bc9d4..5bec04f60 100644 --- a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp @@ -156,9 +156,11 @@ object_ptr GifsListWidget::createFooter() { return std::move(result); } -void GifsListWidget::setVisibleTopBottom(int visibleTop, int visibleBottom) { +void GifsListWidget::visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) { auto top = getVisibleTop(); - Inner::setVisibleTopBottom(visibleTop, visibleBottom); + Inner::visibleTopBottomUpdated(visibleTop, visibleBottom); if (top != getVisibleTop()) { _lastScrolled = getms(); } diff --git a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h index 6dfa4b3d8..58bcef818 100644 --- a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h +++ b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h @@ -51,8 +51,6 @@ public: void clearSelection() override; object_ptr createFooter() override; - void setVisibleTopBottom(int visibleTop, int visibleBottom) override; - void inlineItemLayoutChanged(const InlineBots::Layout::ItemBase *layout) override; void inlineItemRepaint(const InlineBots::Layout::ItemBase *layout) override; bool inlineItemVisible(const InlineBots::Layout::ItemBase *layout) override; @@ -69,6 +67,10 @@ public: ~GifsListWidget(); protected: + void visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) override; + void mousePressEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp index b18d8517f..59ecb375c 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp @@ -468,9 +468,11 @@ object_ptr StickersListWidget::createFooter() { return std::move(result); } -void StickersListWidget::setVisibleTopBottom(int visibleTop, int visibleBottom) { +void StickersListWidget::visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) { auto top = getVisibleTop(); - Inner::setVisibleTopBottom(visibleTop, visibleBottom); + Inner::visibleTopBottomUpdated(visibleTop, visibleBottom); if (_section == Section::Featured) { readVisibleSets(); } diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h index 2359bd068..84c41c4c7 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h @@ -54,8 +54,6 @@ public: void fillIcons(QList &icons); bool preventAutoHide(); - void setVisibleTopBottom(int visibleTop, int visibleBottom) override; - uint64 currentSet(int yOffset) const; void installedLocally(uint64 setId); @@ -65,6 +63,10 @@ public: ~StickersListWidget(); protected: + void visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) override; + void mousePressEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_section.cpp b/Telegram/SourceFiles/chat_helpers/tabbed_section.cpp index 5826c1ab2..3c84f57ef 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_section.cpp +++ b/Telegram/SourceFiles/chat_helpers/tabbed_section.cpp @@ -77,7 +77,7 @@ bool TabbedSection::wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn return _selector->wheelEventFromFloatPlayer(e); } -QRect TabbedSection::rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) { +QRect TabbedSection::rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const { return _selector->rectForFloatPlayer(); } diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_section.h b/Telegram/SourceFiles/chat_helpers/tabbed_section.h index b155fe88b..008e0f8ea 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_section.h +++ b/Telegram/SourceFiles/chat_helpers/tabbed_section.h @@ -44,7 +44,7 @@ public: // Float player interface. bool wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn, Window::Column playerColumn) override; - QRect rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) override; + QRect rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const override; protected: void resizeEvent(QResizeEvent *e) override; diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp b/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp index 9f7e7158c..0cdfb7bc6 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp +++ b/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp @@ -285,7 +285,7 @@ void TabbedSelector::Tab::saveScrollTop() { _scrollTop = widget()->getVisibleTop(); } -TabbedSelector::TabbedSelector(QWidget *parent, not_null controller) : TWidget(parent) +TabbedSelector::TabbedSelector(QWidget *parent, not_null controller) : RpWidget(parent) , _tabsSlider(this, st::emojiTabs) , _topShadow(this, st::shadowFg) , _bottomShadow(this, st::shadowFg) @@ -472,7 +472,7 @@ bool TabbedSelector::wheelEventFromFloatPlayer(QEvent *e) { return _scroll->viewportEvent(e); } -QRect TabbedSelector::rectForFloatPlayer() { +QRect TabbedSelector::rectForFloatPlayer() const { return mapToGlobal(_scroll->geometry()); } @@ -602,9 +602,9 @@ void TabbedSelector::createTabsSlider() { _tabsSlider->setSections(sections); _tabsSlider->setActiveSectionFast(static_cast(_currentTabType)); - _tabsSlider->setSectionActivatedCallback([this] { - switchTab(); - }); + _tabsSlider->sectionActivated() + | rpl::on_next([this](int) { switchTab(); }) + | rpl::start(lifetime()); _tabsSlider->resizeToWidth(width()); _tabsSlider->moveToLeft(0, 0); @@ -701,7 +701,7 @@ TabbedSelector::Inner::Inner(QWidget *parent, not_null cont , _controller(controller) { } -void TabbedSelector::Inner::setVisibleTopBottom(int visibleTop, int visibleBottom) { +void TabbedSelector::Inner::visibleTopBottomUpdated(int visibleTop, int visibleBottom) { auto oldVisibleHeight = getVisibleBottom() - getVisibleTop(); _visibleTop = visibleTop; _visibleBottom = visibleBottom; diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_selector.h b/Telegram/SourceFiles/chat_helpers/tabbed_selector.h index b03d6d2f4..4bb277fca 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_selector.h +++ b/Telegram/SourceFiles/chat_helpers/tabbed_selector.h @@ -20,7 +20,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #pragma once -#include "ui/twidget.h" +#include "ui/rp_widget.h" #include "ui/effects/panel_animation.h" #include "mtproto/sender.h" #include "auth_session.h" @@ -52,7 +52,7 @@ class EmojiListWidget; class StickersListWidget; class GifsListWidget; -class TabbedSelector : public TWidget, private base::Subscriber { +class TabbedSelector : public Ui::RpWidget, private base::Subscriber { Q_OBJECT public: @@ -86,7 +86,7 @@ public: // Float player interface. bool wheelEventFromFloatPlayer(QEvent *e); - QRect rectForFloatPlayer(); + QRect rectForFloatPlayer() const; ~TabbedSelector(); @@ -207,8 +207,6 @@ class TabbedSelector::Inner : public TWidget { public: Inner(QWidget *parent, not_null controller); - void setVisibleTopBottom(int visibleTop, int visibleBottom) override; - int getVisibleTop() const { return _visibleTop; } @@ -235,6 +233,10 @@ signals: void disableScroll(bool disabled); protected: + void visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) override; + not_null controller() const { return _controller; } diff --git a/Telegram/SourceFiles/codegen/lang/generator.cpp b/Telegram/SourceFiles/codegen/lang/generator.cpp index 125f6ef97..54ecf7081 100644 --- a/Telegram/SourceFiles/codegen/lang/generator.cpp +++ b/Telegram/SourceFiles/codegen/lang/generator.cpp @@ -127,7 +127,7 @@ constexpr auto kTagsCount = " << langpack_.tags.size() << ";\n\ } header_->stream() << "\ \n\ -enum LangKey {\n"; +enum LangKey : int {\n"; for (auto &entry : langpack_.entries) { header_->stream() << "\t" << getFullKey(entry) << ",\n"; } diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 284037d78..482c85b07 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -1423,7 +1423,9 @@ PeerData *DialogsInner::updateFromParentDrag(QPoint globalPos) { return nullptr; } -void DialogsInner::setVisibleTopBottom(int visibleTop, int visibleBottom) { +void DialogsInner::visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) { _visibleTop = visibleTop; _visibleBottom = visibleBottom; loadPeerPhotos(); diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h index 31daf10c5..997a08bf3 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h @@ -107,7 +107,6 @@ public: void setLoadMoreCallback(base::lambda callback) { _loadMoreCallback = std::move(callback); } - void setVisibleTopBottom(int visibleTop, int visibleBottom) override; base::Observable searchFromUserChanged; @@ -133,6 +132,10 @@ signals: void refreshHashtags(); protected: + void visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) override; + void paintRegion(Painter &p, const QRegion ®ion, bool paintingOther) override; void mouseMoveEvent(QMouseEvent *e) override; void mousePressEvent(QMouseEvent *e) override; diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 641d59d9e..f77329621 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -271,7 +271,7 @@ bool DialogsWidget::wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn return _scroll->viewportEvent(e); } -QRect DialogsWidget::rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) { +QRect DialogsWidget::rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const { return mapToGlobal(_scroll->geometry()); } diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.h b/Telegram/SourceFiles/dialogs/dialogs_widget.h index 1f0b27a91..3a2342017 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.h @@ -99,7 +99,7 @@ public: // Float player interface. bool wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn, Window::Column playerColumn) override; - QRect rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) override; + QRect rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const override; void notify_userIsContactChanged(UserData *user, bool fromThisApp); void notify_historyMuteUpdated(History *history); diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index 25a4c4a86..2abbde103 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -18,6 +18,8 @@ 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-2017 John Preston, https://desktop.telegram.org */ +#include "facades.h" + #include "profile/profile_section_memento.h" #include "core/click_handler_types.h" #include "media/media_clip_reader.h" diff --git a/Telegram/SourceFiles/history/history_admin_log_inner.cpp b/Telegram/SourceFiles/history/history_admin_log_inner.cpp index f338d8335..2570bf7a0 100644 --- a/Telegram/SourceFiles/history/history_admin_log_inner.cpp +++ b/Telegram/SourceFiles/history/history_admin_log_inner.cpp @@ -233,7 +233,9 @@ InnerWidget::InnerWidget(QWidget *parent, not_null controll requestAdmins(); } -void InnerWidget::setVisibleTopBottom(int visibleTop, int visibleBottom) { +void InnerWidget::visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) { auto scrolledUp = (visibleTop < _visibleTop); _visibleTop = visibleTop; _visibleBottom = visibleBottom; diff --git a/Telegram/SourceFiles/history/history_admin_log_inner.h b/Telegram/SourceFiles/history/history_admin_log_inner.h index b9a427c40..2a5ce5eac 100644 --- a/Telegram/SourceFiles/history/history_admin_log_inner.h +++ b/Telegram/SourceFiles/history/history_admin_log_inner.h @@ -50,9 +50,6 @@ public: return _channel; } - // Updates the area that is visible inside the scroll container. - void setVisibleTopBottom(int visibleTop, int visibleBottom) override; - // Set the correct scroll position after being resized. void restoreScrollPosition(); @@ -76,6 +73,10 @@ public: ~InnerWidget(); protected: + void visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) override; + void paintEvent(QPaintEvent *e) override; void keyPressEvent(QKeyEvent *e) override; void mousePressEvent(QMouseEvent *e) override; diff --git a/Telegram/SourceFiles/history/history_admin_log_section.cpp b/Telegram/SourceFiles/history/history_admin_log_section.cpp index 1e1d9175f..17a4db701 100644 --- a/Telegram/SourceFiles/history/history_admin_log_section.cpp +++ b/Telegram/SourceFiles/history/history_admin_log_section.cpp @@ -431,7 +431,7 @@ bool Widget::wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn, Windo return _scroll->viewportEvent(e); } -QRect Widget::rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) { +QRect Widget::rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const { return mapToGlobal(_scroll->geometry()); } diff --git a/Telegram/SourceFiles/history/history_admin_log_section.h b/Telegram/SourceFiles/history/history_admin_log_section.h index 327f22a4f..d9d0c7668 100644 --- a/Telegram/SourceFiles/history/history_admin_log_section.h +++ b/Telegram/SourceFiles/history/history_admin_log_section.h @@ -102,7 +102,7 @@ public: // Float player interface. bool wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn, Window::Column playerColumn) override; - QRect rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) override; + QRect rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const override; void applyFilter(FilterValue &&value); diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index e6e6056fc..fb41850fe 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -3515,7 +3515,7 @@ bool HistoryWidget::wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn return _scroll->viewportEvent(e); } -QRect HistoryWidget::rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) { +QRect HistoryWidget::rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const { if (playerColumn == Window::Column::Third && _tabbedSection) { auto tabbedColumn = (myColumn == Window::Column::First) ? Window::Column::Second : Window::Column::Third; return _tabbedSection->rectForFloatPlayer(tabbedColumn, playerColumn); diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index cd06a8ead..390ea1ee8 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -348,7 +348,7 @@ public: // Float player interface. bool wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn, Window::Column playerColumn) override; - QRect rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) override; + QRect rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const override; void app_sendBotCallback(const HistoryMessageReplyMarkup::Button *button, not_null msg, int row, int col); diff --git a/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp b/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp index a9548b8f0..378f05e79 100644 --- a/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp @@ -80,7 +80,9 @@ Inner::Inner(QWidget *parent, not_null controller) : TWidge })); } -void Inner::setVisibleTopBottom(int visibleTop, int visibleBottom) { +void Inner::visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) { _visibleBottom = visibleBottom; if (_visibleTop != visibleTop) { _visibleTop = visibleTop; diff --git a/Telegram/SourceFiles/inline_bots/inline_results_widget.h b/Telegram/SourceFiles/inline_bots/inline_results_widget.h index 6316c8836..7376e254c 100644 --- a/Telegram/SourceFiles/inline_bots/inline_results_widget.h +++ b/Telegram/SourceFiles/inline_bots/inline_results_widget.h @@ -74,7 +74,6 @@ public: void hideInlineRowsPanel(); void clearInlineRowsPanel(); - void setVisibleTopBottom(int visibleTop, int visibleBottom) override; void preloadImages(); void inlineItemLayoutChanged(const ItemBase *layout) override; @@ -90,6 +89,10 @@ public: ~Inner(); protected: + void visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) override; + void mousePressEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; diff --git a/Telegram/SourceFiles/lang/lang_instance.cpp b/Telegram/SourceFiles/lang/lang_instance.cpp index 08a7f75f7..850202edf 100644 --- a/Telegram/SourceFiles/lang/lang_instance.cpp +++ b/Telegram/SourceFiles/lang/lang_instance.cpp @@ -499,4 +499,14 @@ Instance &Current() { return Messenger::Instance().langpack(); } +rpl::producer Viewer(LangKey key) { + return + rpl::single(Current().getValue(key)) + | then( + base::ObservableViewer(Current().updated()) + | rpl::map([=](auto&&) { + return Current().getValue(key); + })); +} + } // namespace Lang diff --git a/Telegram/SourceFiles/lang/lang_instance.h b/Telegram/SourceFiles/lang/lang_instance.h index 2bd5a001f..e67650706 100644 --- a/Telegram/SourceFiles/lang/lang_instance.h +++ b/Telegram/SourceFiles/lang/lang_instance.h @@ -20,6 +20,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #pragma once +#include #include "lang_auto.h" #include "base/weak_unique_ptr.h" @@ -48,6 +49,8 @@ QString DefaultLanguageId(); class Instance; Instance &Current(); +rpl::producer Viewer(LangKey key); + class Instance { public: Instance() { @@ -84,15 +87,20 @@ public: return _updated; } - QString getValue(LangKey key) { + QString getValue(LangKey key) const { Expects(key >= 0 && key < kLangKeysCount); Expects(_values.size() == kLangKeysCount); return _values[key]; } - bool isNonDefaultPlural(LangKey key) { + bool isNonDefaultPlural(LangKey key) const { Expects(key >= 0 && key < kLangKeysCount); Expects(_nonDefaultSet.size() == kLangKeysCount); - return _nonDefaultSet[key] || _nonDefaultSet[key + 1] || _nonDefaultSet[key + 2] || _nonDefaultSet[key + 3] || _nonDefaultSet[key + 4] || _nonDefaultSet[key + 5]; + return _nonDefaultSet[key] + || _nonDefaultSet[key + 1] + || _nonDefaultSet[key + 2] + || _nonDefaultSet[key + 3] + || _nonDefaultSet[key + 4] + || _nonDefaultSet[key + 5]; } private: diff --git a/Telegram/SourceFiles/layerwidget.cpp b/Telegram/SourceFiles/layerwidget.cpp index e4df03910..93ed128a2 100644 --- a/Telegram/SourceFiles/layerwidget.cpp +++ b/Telegram/SourceFiles/layerwidget.cpp @@ -388,6 +388,7 @@ void LayerStackWidget::setCacheImages() { auto bodyCache = QPixmap(), mainMenuCache = QPixmap(); auto specialLayerCache = QPixmap(); if (_specialLayer) { + myEnsureResized(_specialLayer); auto sides = RectPart::Left | RectPart::Right; if (_specialLayer->y() > 0) { sides |= RectPart::Top; @@ -673,6 +674,7 @@ void LayerStackWidget::initChildLayer(LayerWidget *layer) { layer->setClosedCallback([this, layer] { onLayerClosed(layer); }); layer->setResizedCallback([this] { onLayerResized(); }); connect(layer, SIGNAL(destroyed(QObject*)), this, SLOT(onLayerDestroyed(QObject*))); + myEnsureResized(layer); layer->parentResized(); } diff --git a/Telegram/SourceFiles/layerwidget.h b/Telegram/SourceFiles/layerwidget.h index a516bdc4d..0e8375e95 100644 --- a/Telegram/SourceFiles/layerwidget.h +++ b/Telegram/SourceFiles/layerwidget.h @@ -20,16 +20,16 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #pragma once +#include "ui/rp_widget.h" + namespace Window { class MainMenu; class Controller; } // namespace Window -class LayerWidget : public TWidget { - Q_OBJECT - +class LayerWidget : public Ui::RpWidget { public: - using TWidget::TWidget; + using RpWidget::RpWidget; virtual void parentResized() = 0; virtual void showFinished() { diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index bb02010b2..13b0f7f09 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -119,7 +119,10 @@ MainWidget::Float::Float(QWidget *parent, HistoryItem *item, ToggleCallback togg }) { } -MainWidget::MainWidget(QWidget *parent, not_null controller) : TWidget(parent) +MainWidget::MainWidget( + QWidget *parent, + not_null controller) +: RpWidget(parent) , _controller(controller) , _dialogsWidth(st::dialogsWidthMin) , _sideShadow(this, st::shadowFg) @@ -1813,7 +1816,10 @@ void MainWidget::createPlayer() { return; } if (!_player) { - _player.create(this, [this] { playerHeightUpdated(); }); + _player.create(this); + _player->heightValue() + | rpl::on_next([this](int) { playerHeightUpdated(); }) + | rpl::start(lifetime()); _player->entity()->setCloseCallback([this] { closeBothPlayers(); }); _playerVolume.create(this); _player->entity()->volumeWidgetCreated(_playerVolume); @@ -1870,7 +1876,12 @@ void MainWidget::setCurrentCall(Calls::Call *call) { void MainWidget::createCallTopBar() { Expects(_currentCall != nullptr); - _callTopBar.create(this, object_ptr(this, _currentCall), style::margins(0, 0, 0, 0), [this] { callTopBarHeightUpdated(); }); + _callTopBar.create(this, object_ptr(this, _currentCall)); + _callTopBar->heightValue() + | rpl::on_next([this](int value) { + callTopBarHeightUpdated(value); + }) + | rpl::start(lifetime()); orderWidgets(); if (_a_show.animating()) { _callTopBar->showFast(); @@ -1889,8 +1900,7 @@ void MainWidget::destroyCallTopBar() { } } -void MainWidget::callTopBarHeightUpdated() { - auto callTopBarHeight = _callTopBar ? _callTopBar->height() : 0; +void MainWidget::callTopBarHeightUpdated(int callTopBarHeight) { if (!callTopBarHeight && !_currentCall) { _callTopBar.destroyDelayed(); } diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 5bc2d5052..575932495 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -24,6 +24,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "history/history_common.h" #include "core/single_timer.h" #include "base/weak_unique_ptr.h" +#include "ui/rp_widget.h" namespace Notify { struct PeerUpdate; @@ -46,7 +47,7 @@ namespace Ui { class PlainShadow; class DropdownMenu; template -class WidgetSlideWrap; +class SlideWrap; } // namespace Ui namespace Window { @@ -149,7 +150,7 @@ class ItemBase; } // namespace Layout } // namespace InlineBots -class MainWidget : public TWidget, public RPCSender, private base::Subscriber { +class MainWidget : public Ui::RpWidget, public RPCSender, private base::Subscriber { Q_OBJECT public: @@ -506,7 +507,7 @@ private: void setCurrentCall(Calls::Call *call); void createCallTopBar(); void destroyCallTopBar(); - void callTopBarHeightUpdated(); + void callTopBarHeightUpdated(int callTopBarHeight); void sendReadRequest(PeerData *peer, MsgId upTo); void channelReadDone(PeerData *peer, const MTPBool &result); @@ -620,7 +621,7 @@ private: object_ptr _overview = { nullptr }; base::weak_unique_ptr _currentCall; - object_ptr> _callTopBar = { nullptr }; + object_ptr> _callTopBar = { nullptr }; object_ptr _player = { nullptr }; object_ptr _playerVolume = { nullptr }; diff --git a/Telegram/SourceFiles/media/player/media_player_widget.cpp b/Telegram/SourceFiles/media/player/media_player_widget.cpp index a8976c373..0e3d5a18d 100644 --- a/Telegram/SourceFiles/media/player/media_player_widget.cpp +++ b/Telegram/SourceFiles/media/player/media_player_widget.cpp @@ -84,7 +84,7 @@ QPoint Widget::PlayButton::prepareRippleStartPosition() const { return QPoint(mapFromGlobal(QCursor::pos()) - st::mediaPlayerButton.rippleAreaPosition); } -Widget::Widget(QWidget *parent) : TWidget(parent) +Widget::Widget(QWidget *parent) : RpWidget(parent) , _nameLabel(this, st::mediaPlayerName) , _timeLabel(this, st::mediaPlayerTime) , _playPause(this) diff --git a/Telegram/SourceFiles/media/player/media_player_widget.h b/Telegram/SourceFiles/media/player/media_player_widget.h index 75a93fd29..f128642fd 100644 --- a/Telegram/SourceFiles/media/player/media_player_widget.h +++ b/Telegram/SourceFiles/media/player/media_player_widget.h @@ -20,6 +20,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #pragma once +#include "ui/rp_widget.h" + class AudioMsgId; namespace Ui { @@ -41,7 +43,7 @@ class PlayButton; class VolumeWidget; struct TrackState; -class Widget : public TWidget, private base::Subscriber { +class Widget : public Ui::RpWidget, private base::Subscriber { public: Widget(QWidget *parent); diff --git a/Telegram/SourceFiles/overviewwidget.cpp b/Telegram/SourceFiles/overviewwidget.cpp index d05e0bb6a..1e036afa5 100644 --- a/Telegram/SourceFiles/overviewwidget.cpp +++ b/Telegram/SourceFiles/overviewwidget.cpp @@ -2149,7 +2149,7 @@ bool OverviewWidget::wheelEventFromFloatPlayer(QEvent *e, Window::Column myColum return _scroll->viewportEvent(e); } -QRect OverviewWidget::rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) { +QRect OverviewWidget::rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const { return mapToGlobal(_scroll->geometry()); } diff --git a/Telegram/SourceFiles/overviewwidget.h b/Telegram/SourceFiles/overviewwidget.h index adde68249..c17515353 100644 --- a/Telegram/SourceFiles/overviewwidget.h +++ b/Telegram/SourceFiles/overviewwidget.h @@ -350,7 +350,7 @@ public: // Float player interface. bool wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn, Window::Column playerColumn) override; - QRect rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) override; + QRect rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const override; void ui_repaintHistoryItem(not_null item); diff --git a/Telegram/SourceFiles/profile/profile_block_info.cpp b/Telegram/SourceFiles/profile/profile_block_info.cpp index d638790b4..ea521500d 100644 --- a/Telegram/SourceFiles/profile/profile_block_info.cpp +++ b/Telegram/SourceFiles/profile/profile_block_info.cpp @@ -23,7 +23,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "styles/style_profile.h" #include "ui/widgets/labels.h" #include "ui/widgets/buttons.h" -#include "ui/effects/widget_slide_wrap.h" +#include "ui/wrap/slide_wrap.h" #include "core/click_handler_types.h" #include "mainwidget.h" #include "observer_peer.h" diff --git a/Telegram/SourceFiles/profile/profile_block_peer_list.cpp b/Telegram/SourceFiles/profile/profile_block_peer_list.cpp index d4a0cd5b7..c5642e82e 100644 --- a/Telegram/SourceFiles/profile/profile_block_peer_list.cpp +++ b/Telegram/SourceFiles/profile/profile_block_peer_list.cpp @@ -50,7 +50,7 @@ int PeerListWidget::resizeGetHeight(int newWidth) { return newHeight + _st.bottom; } -void PeerListWidget::setVisibleTopBottom(int visibleTop, int visibleBottom) { +void PeerListWidget::visibleTopBottomUpdated(int visibleTop, int visibleBottom) { _visibleTop = visibleTop; _visibleBottom = visibleBottom; diff --git a/Telegram/SourceFiles/profile/profile_block_peer_list.h b/Telegram/SourceFiles/profile/profile_block_peer_list.h index 879c76be8..1779131f6 100644 --- a/Telegram/SourceFiles/profile/profile_block_peer_list.h +++ b/Telegram/SourceFiles/profile/profile_block_peer_list.h @@ -38,8 +38,6 @@ class PeerListWidget : public BlockWidget { public: PeerListWidget(QWidget *parent, PeerData *peer, const QString &title, const style::ProfilePeerListItem &st = st::profileMemberItem, const QString &removeText = QString()); - void setVisibleTopBottom(int visibleTop, int visibleBottom) override; - struct Item { explicit Item(PeerData *peer); ~Item(); @@ -100,12 +98,14 @@ public: } protected: + int resizeGetHeight(int newWidth) override; + void visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) override; + void paintOutlinedRect(Painter &p, int x, int y, int w, int h) const; void refreshVisibility(); - // Resizes content and counts natural widget height for the desired width. - int resizeGetHeight(int newWidth) override; - void paintContents(Painter &p) override; void mouseMoveEvent(QMouseEvent *e) override; diff --git a/Telegram/SourceFiles/profile/profile_common_groups_section.cpp b/Telegram/SourceFiles/profile/profile_common_groups_section.cpp index 25a9c7f2a..baeb70ab9 100644 --- a/Telegram/SourceFiles/profile/profile_common_groups_section.cpp +++ b/Telegram/SourceFiles/profile/profile_common_groups_section.cpp @@ -105,7 +105,9 @@ InnerWidget::InnerWidget(QWidget *parent, not_null user) : TWidget(pa _contentTop = st::profileCommonGroupsSkip; } -void InnerWidget::setVisibleTopBottom(int visibleTop, int visibleBottom) { +void InnerWidget::visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) { _visibleTop = visibleTop; _visibleBottom = visibleBottom; @@ -449,7 +451,7 @@ bool Widget::wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn, Windo return _scroll->viewportEvent(e); } -QRect Widget::rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) { +QRect Widget::rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const { return mapToGlobal(_scroll->geometry()); } diff --git a/Telegram/SourceFiles/profile/profile_common_groups_section.h b/Telegram/SourceFiles/profile/profile_common_groups_section.h index a23a61488..b81ceb0a0 100644 --- a/Telegram/SourceFiles/profile/profile_common_groups_section.h +++ b/Telegram/SourceFiles/profile/profile_common_groups_section.h @@ -102,9 +102,6 @@ public: return _user; } - // Updates the area that is visible inside the scroll container. - void setVisibleTopBottom(int visibleTop, int visibleBottom) override; - void resizeToWidth(int newWidth, int minHeight) { _minHeight = minHeight; return TWidget::resizeToWidth(newWidth); @@ -119,15 +116,17 @@ signals: void cancelled(); protected: + int resizeGetHeight(int newWidth) override; + void visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) override; + void paintEvent(QPaintEvent *e) override; void keyPressEvent(QKeyEvent *e) override; void mousePressEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; - // Resizes content and counts natural widget height for the desired width. - int resizeGetHeight(int newWidth) override; - private: void updateSelected(QPoint localPos); void updateRow(int index); @@ -191,7 +190,7 @@ public: // Float player interface. bool wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn, Window::Column playerColumn) override; - QRect rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) override; + QRect rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const override; protected: void resizeEvent(QResizeEvent *e) override; diff --git a/Telegram/SourceFiles/profile/profile_inner_widget.cpp b/Telegram/SourceFiles/profile/profile_inner_widget.cpp index 07abb9565..1726e03f0 100644 --- a/Telegram/SourceFiles/profile/profile_inner_widget.cpp +++ b/Telegram/SourceFiles/profile/profile_inner_widget.cpp @@ -70,7 +70,7 @@ void InnerWidget::createBlocks() { } } -void InnerWidget::setVisibleTopBottom(int visibleTop, int visibleBottom) { +void InnerWidget::visibleTopBottomUpdated(int visibleTop, int visibleBottom) { _visibleTop = visibleTop; _visibleBottom = visibleBottom; diff --git a/Telegram/SourceFiles/profile/profile_inner_widget.h b/Telegram/SourceFiles/profile/profile_inner_widget.h index b230b4e1e..6d3b62a8c 100644 --- a/Telegram/SourceFiles/profile/profile_inner_widget.h +++ b/Telegram/SourceFiles/profile/profile_inner_widget.h @@ -41,9 +41,6 @@ public: return TWidget::resizeToWidth(newWidth); } - // Updates the area that is visible inside the scroll container. - void setVisibleTopBottom(int visibleTop, int visibleBottom) override; - // Profile fixed top bar should use this flag to decide // if it shows "Share contact" button or not. // It should show it only if it is hidden in the cover. @@ -61,12 +58,14 @@ private slots: void onBlockHeightUpdated(); protected: + int resizeGetHeight(int newWidth) override; + void visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) override; + void paintEvent(QPaintEvent *e) override; void keyPressEvent(QKeyEvent *e) override; - // Resizes content and counts natural widget height for the desired width. - int resizeGetHeight(int newWidth) override; - private: void createBlocks(); diff --git a/Telegram/SourceFiles/profile/profile_userpic_button.cpp b/Telegram/SourceFiles/profile/profile_userpic_button.cpp index 005ec009a..ddfa9ab40 100644 --- a/Telegram/SourceFiles/profile/profile_userpic_button.cpp +++ b/Telegram/SourceFiles/profile/profile_userpic_button.cpp @@ -26,7 +26,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org namespace Profile { -UserpicButton::UserpicButton(QWidget *parent, PeerData *peer, int size) : AbstractButton(parent) +UserpicButton::UserpicButton(QWidget *parent, not_null peer, int size) : AbstractButton(parent) , _size(size ? size : st::profilePhotoSize) , _peer(peer) { resize(_size, _size); diff --git a/Telegram/SourceFiles/profile/profile_userpic_button.h b/Telegram/SourceFiles/profile/profile_userpic_button.h index 6e710785e..695c8db5d 100644 --- a/Telegram/SourceFiles/profile/profile_userpic_button.h +++ b/Telegram/SourceFiles/profile/profile_userpic_button.h @@ -31,7 +31,7 @@ namespace Profile { class UserpicButton : public Ui::AbstractButton, private base::Subscriber { public: - UserpicButton(QWidget *parent, PeerData *peer, int size = 0); + UserpicButton(QWidget *parent, not_null peer, int size = 0); // If at the first moment the _userpic was not loaded, // we need to show it animated after the profile is fully shown. @@ -51,7 +51,7 @@ private: bool _notShownYet; int _size = 0; - PeerData *_peer; + not_null _peer; bool _waiting = false; QPixmap _userpic, _oldUserpic; Animation _a_appearance; diff --git a/Telegram/SourceFiles/profile/profile_widget.cpp b/Telegram/SourceFiles/profile/profile_widget.cpp index f9dc74c9d..dc6324d32 100644 --- a/Telegram/SourceFiles/profile/profile_widget.cpp +++ b/Telegram/SourceFiles/profile/profile_widget.cpp @@ -165,7 +165,7 @@ bool Widget::wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn, Windo return _scroll->viewportEvent(e); } -QRect Widget::rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) { +QRect Widget::rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const { return mapToGlobal(_scroll->geometry()); } diff --git a/Telegram/SourceFiles/profile/profile_widget.h b/Telegram/SourceFiles/profile/profile_widget.h index 6ce454a4b..062de6e82 100644 --- a/Telegram/SourceFiles/profile/profile_widget.h +++ b/Telegram/SourceFiles/profile/profile_widget.h @@ -56,7 +56,7 @@ public: // Float player interface. bool wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn, Window::Column playerColumn) override; - QRect rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) override; + QRect rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const override; protected: void resizeEvent(QResizeEvent *e) override; diff --git a/Telegram/SourceFiles/rpl/event_stream.h b/Telegram/SourceFiles/rpl/event_stream.h index 0d17925f7..947eb6198 100644 --- a/Telegram/SourceFiles/rpl/event_stream.h +++ b/Telegram/SourceFiles/rpl/event_stream.h @@ -143,8 +143,8 @@ std::weak_ptr>> event_stream::weak( template event_stream::~event_stream() { - if (_consumers) { - for (auto &consumer : *_consumers) { + if (auto consumers = base::take(_consumers)) { + for (auto &consumer : *consumers) { consumer.put_done(); } } diff --git a/Telegram/SourceFiles/settings/settings_advanced_widget.cpp b/Telegram/SourceFiles/settings/settings_advanced_widget.cpp index 4cbe7ca08..397b3f2e3 100644 --- a/Telegram/SourceFiles/settings/settings_advanced_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_advanced_widget.cpp @@ -28,7 +28,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "boxes/local_storage_box.h" #include "mainwindow.h" #include "ui/widgets/buttons.h" -#include "ui/effects/widget_slide_wrap.h" +#include "ui/wrap/slide_wrap.h" #include "storage/localstorage.h" #include "window/themes/window_theme.h" @@ -62,31 +62,31 @@ void AdvancedWidget::createControls() { #endif // TDESKTOP_DISABLE_NETWORK_PROXY })(); if (self()) { - addChildRow(_manageLocalStorage, marginLocalStorage, lang(lng_settings_manage_local_storage), SLOT(onManageLocalStorage())); + createChildRow(_manageLocalStorage, marginLocalStorage, lang(lng_settings_manage_local_storage), SLOT(onManageLocalStorage())); } #ifndef TDESKTOP_DISABLE_NETWORK_PROXY - addChildRow(_connectionType, marginLarge, lang(lng_connection_type), lang(lng_connection_auto_connecting), LabeledLink::Type::Primary, SLOT(onConnectionType())); + createChildRow(_connectionType, marginLarge, lang(lng_connection_type), lang(lng_connection_auto_connecting), LabeledLink::Type::Primary, SLOT(onConnectionType())); connectionTypeUpdated(); #endif // !TDESKTOP_DISABLE_NETWORK_PROXY if (self()) { - addChildRow(_askQuestion, marginSmall, lang(lng_settings_ask_question), SLOT(onAskQuestion())); + createChildRow(_askQuestion, marginSmall, lang(lng_settings_ask_question), SLOT(onAskQuestion())); } else { style::margins slidedPadding(0, marginLarge.bottom() / 2, 0, marginLarge.bottom() - (marginLarge.bottom() / 2)); - addChildRow(_useDefaultTheme, marginLarge, slidedPadding, lang(lng_settings_bg_use_default), SLOT(onUseDefaultTheme())); + createChildRow(_useDefaultTheme, marginLarge, slidedPadding, lang(lng_settings_bg_use_default), SLOT(onUseDefaultTheme())); if (!Window::Theme::IsNonDefaultUsed()) { _useDefaultTheme->hideFast(); } - addChildRow(_toggleNightTheme, marginLarge, slidedPadding, getNightThemeToggleText(), SLOT(onToggleNightTheme())); + createChildRow(_toggleNightTheme, marginLarge, slidedPadding, getNightThemeToggleText(), SLOT(onToggleNightTheme())); if (Window::Theme::IsNonDefaultUsed()) { _toggleNightTheme->hideFast(); } } - addChildRow(_telegramFAQ, marginLarge, lang(lng_settings_faq), SLOT(onTelegramFAQ())); + createChildRow(_telegramFAQ, marginLarge, lang(lng_settings_faq), SLOT(onTelegramFAQ())); if (self()) { style::margins marginLogout(0, 0, 0, 2 * st::settingsLargeSkip); - addChildRow(_logOut, marginLogout, lang(lng_settings_logout), SLOT(onLogOut())); + createChildRow(_logOut, marginLogout, lang(lng_settings_logout), SLOT(onLogOut())); } } diff --git a/Telegram/SourceFiles/settings/settings_advanced_widget.h b/Telegram/SourceFiles/settings/settings_advanced_widget.h index 5c4a9a486..4f3b20210 100644 --- a/Telegram/SourceFiles/settings/settings_advanced_widget.h +++ b/Telegram/SourceFiles/settings/settings_advanced_widget.h @@ -52,15 +52,15 @@ private: void supportGot(const MTPhelp_Support &support); QString getNightThemeToggleText() const; - object_ptr _manageLocalStorage = { nullptr }; + Ui::LinkButton *_manageLocalStorage = nullptr; #ifndef TDESKTOP_DISABLE_NETWORK_PROXY - object_ptr _connectionType = { nullptr }; + LabeledLink *_connectionType = nullptr; #endif // !TDESKTOP_DISABLE_NETWORK_PROXY - object_ptr> _useDefaultTheme = { nullptr }; - object_ptr> _toggleNightTheme = { nullptr }; - object_ptr _askQuestion = { nullptr }; - object_ptr _telegramFAQ = { nullptr }; - object_ptr _logOut = { nullptr }; + Ui::SlideWrap *_useDefaultTheme = nullptr; + Ui::SlideWrap *_toggleNightTheme = nullptr; + Ui::LinkButton *_askQuestion = nullptr; + Ui::LinkButton *_telegramFAQ = nullptr; + Ui::LinkButton *_logOut = nullptr; mtpRequestId _supportGetRequest = 0; diff --git a/Telegram/SourceFiles/settings/settings_background_widget.cpp b/Telegram/SourceFiles/settings/settings_background_widget.cpp index b9ea8150f..5125e391b 100644 --- a/Telegram/SourceFiles/settings/settings_background_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_background_widget.cpp @@ -24,7 +24,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "lang/lang_keys.h" #include "mainwidget.h" #include "boxes/background_box.h" -#include "ui/effects/widget_slide_wrap.h" +#include "ui/wrap/slide_wrap.h" #include "ui/widgets/checkbox.h" #include "ui/widgets/buttons.h" #include "storage/localstorage.h" @@ -35,7 +35,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org namespace Settings { -BackgroundRow::BackgroundRow(QWidget *parent) : TWidget(parent) +BackgroundRow::BackgroundRow(QWidget *parent) : RpWidget(parent) , _chooseFromGallery(this, lang(lng_settings_bg_from_gallery), st::boxLinkButton) , _chooseFromFile(this, lang(lng_settings_bg_from_file), st::boxLinkButton) , _editTheme(this, lang(lng_settings_bg_edit_theme), st::boxLinkButton) @@ -216,14 +216,14 @@ void BackgroundWidget::createControls() { style::margins margin(0, 0, 0, st::settingsSmallSkip); style::margins slidedPadding(0, margin.bottom() / 2, 0, margin.bottom() - (margin.bottom() / 2)); - addChildRow(_background, margin); + createChildRow(_background, margin); connect(_background, SIGNAL(chooseFromGallery()), this, SLOT(onChooseFromGallery())); connect(_background, SIGNAL(chooseFromFile()), this, SLOT(onChooseFromFile())); connect(_background, SIGNAL(editTheme()), this, SLOT(onEditTheme())); connect(_background, SIGNAL(useDefault()), this, SLOT(onUseDefaultTheme())); - addChildRow(_tile, margin, lang(lng_settings_bg_tile), [this](bool) { onTile(); }, Window::Theme::Background()->tile()); - addChildRow(_adaptive, margin, slidedPadding, lang(lng_settings_adaptive_wide), [this](bool) { onAdaptive(); }, Global::AdaptiveForWide()); + createChildRow(_tile, margin, lang(lng_settings_bg_tile), [this](bool) { onTile(); }, Window::Theme::Background()->tile()); + createChildRow(_adaptive, margin, slidedPadding, lang(lng_settings_adaptive_wide), [this](bool) { onAdaptive(); }, Global::AdaptiveForWide()); if (Global::AdaptiveChatLayout() != Adaptive::ChatLayout::Wide) { _adaptive->hideFast(); } diff --git a/Telegram/SourceFiles/settings/settings_background_widget.h b/Telegram/SourceFiles/settings/settings_background_widget.h index 93fb5091f..c7b52f579 100644 --- a/Telegram/SourceFiles/settings/settings_background_widget.h +++ b/Telegram/SourceFiles/settings/settings_background_widget.h @@ -22,10 +22,11 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "settings/settings_block_widget.h" #include "ui/effects/radial_animation.h" +#include "ui/rp_widget.h" namespace Settings { -class BackgroundRow : public TWidget, private base::Subscriber { +class BackgroundRow : public Ui::RpWidget, private base::Subscriber { Q_OBJECT public: @@ -82,9 +83,9 @@ private: void createControls(); void needBackgroundUpdate(bool tile); - object_ptr _background = { nullptr }; - object_ptr _tile = { nullptr }; - object_ptr> _adaptive = { nullptr }; + BackgroundRow *_background = nullptr; + Ui::Checkbox *_tile = nullptr; + Ui::SlideWrap *_adaptive = nullptr; }; diff --git a/Telegram/SourceFiles/settings/settings_block_widget.cpp b/Telegram/SourceFiles/settings/settings_block_widget.cpp index 36da0365f..61c238994 100644 --- a/Telegram/SourceFiles/settings/settings_block_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_block_widget.cpp @@ -23,12 +23,19 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "styles/style_settings.h" #include "ui/widgets/checkbox.h" #include "ui/widgets/buttons.h" +#include "ui/wrap/vertical_layout.h" namespace Settings { -BlockWidget::BlockWidget(QWidget *parent, UserData *self, const QString &title) : TWidget(parent) +BlockWidget::BlockWidget(QWidget *parent, UserData *self, const QString &title) : RpWidget(parent) , _self(self) -, _title(title) { +, _title(title) +, _content(this) { + _content->heightValue() + | rpl::on_next([this](int contentHeight) { + resize(width(), contentTop() + contentHeight + st::settingsBlockMarginBottom); + }) + | rpl::start(lifetime()); } void BlockWidget::setContentLeft(int contentLeft) { @@ -42,21 +49,25 @@ int BlockWidget::contentTop() const { int BlockWidget::resizeGetHeight(int newWidth) { int x = contentLeft(), result = contentTop(); int availw = newWidth - x; - for_const (auto &row, _rows) { - auto childMargins = row.child->getMargins(); - row.child->moveToLeft(x + row.margin.left(), result + row.margin.top(), newWidth); - auto availRowWidth = availw - row.margin.left() - row.margin.right() - x; - auto natural = row.child->naturalWidth(); - auto rowWidth = (natural < 0) ? availRowWidth : qMin(natural, availRowWidth); - if (row.child->widthNoMargins() != rowWidth) { - row.child->resizeToWidth(rowWidth); - } - result += row.margin.top() + row.child->heightNoMargins() + row.margin.bottom(); - } - result += st::settingsBlockMarginBottom; + + auto margins = getMargins(); + + _content->resizeToWidth(availw); + _content->moveToLeft(margins.left() + x, margins.top() + result, newWidth); + result += _content->heightNoMargins() + st::settingsBlockMarginBottom; + return result; } +QMargins BlockWidget::getMargins() const { + auto result = _content->getMargins(); + return QMargins( + result.left(), + qMax(result.top() - contentTop(), 0), + result.right(), + qMax(result.bottom() - st::settingsBlockMarginBottom, 0)); +} + void BlockWidget::paintEvent(QPaintEvent *e) { Painter p(this); @@ -69,28 +80,37 @@ void BlockWidget::paintTitle(Painter &p) { p.setFont(st::settingsBlockTitleFont); p.setPen(st::settingsBlockTitleFg); - int titleTop = st::settingsBlockMarginTop + st::settingsBlockTitleTop; - p.drawTextLeft(contentLeft(), titleTop, width(), _title); + auto margins = getMargins(); + auto titleTop = st::settingsBlockMarginTop + st::settingsBlockTitleTop; + p.drawTextLeft( + margins.left() + contentLeft(), + margins.top() + titleTop, + width(), + _title); } -void BlockWidget::addCreatedRow(TWidget *child, const style::margins &margin) { - _rows.push_back({ child, margin }); +Ui::RpWidget *BlockWidget::addCreatedRow( + object_ptr row, + const style::margins &margin) { + return _content->add(std::move(row), margin); } -void BlockWidget::rowHeightUpdated() { - auto newHeight = resizeGetHeight(width()); - if (newHeight != height()) { - resize(width(), newHeight); - emit heightUpdated(); - } -} - -void BlockWidget::createChildRow(object_ptr &child, style::margins &margin, const QString &text, base::lambda callback, bool checked) { +void BlockWidget::createChildWidget( + object_ptr &child, + style::margins &margin, + const QString &text, + base::lambda callback, + bool checked) { child.create(this, text, checked, st::defaultBoxCheckbox); subscribe(child->checkedChanged, std::move(callback)); } -void BlockWidget::createChildRow(object_ptr &child, style::margins &margin, const QString &text, const char *slot, const style::LinkButton &st) { +void BlockWidget::createChildWidget( + object_ptr &child, + style::margins &margin, + const QString &text, + const char *slot, + const style::LinkButton &st) { child.create(this, text, st); connect(child, SIGNAL(clicked()), this, slot); } diff --git a/Telegram/SourceFiles/settings/settings_block_widget.h b/Telegram/SourceFiles/settings/settings_block_widget.h index 77cdfe689..33b106936 100644 --- a/Telegram/SourceFiles/settings/settings_block_widget.h +++ b/Telegram/SourceFiles/settings/settings_block_widget.h @@ -21,6 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #pragma once #include "base/observer.h" +#include "ui/rp_widget.h" #include "styles/style_boxes.h" namespace Ui { @@ -33,19 +34,20 @@ class RadioenumGroup; template class Radioenum; template -class WidgetSlideWrap; +class SlideWrap; +class VerticalLayout; } // namespace Ui namespace Settings { -class BlockWidget : public TWidget, protected base::Subscriber { - Q_OBJECT - +class BlockWidget : public Ui::RpWidget, protected base::Subscriber { public: BlockWidget(QWidget *parent, UserData *self, const QString &title); void setContentLeft(int contentLeft); + QMargins getMargins() const override; + protected: void paintEvent(QPaintEvent *e) override; virtual void paintContents(Painter &p) { @@ -60,11 +62,6 @@ protected: // Resizes content and counts natural widget height for the desired width. int resizeGetHeight(int newWidth) override; - void contentSizeUpdated() { - resizeToWidth(width()); - emit heightUpdated(); - } - UserData *self() const { return _self; } @@ -74,39 +71,67 @@ protected: } template - Widget *addChildRow(object_ptr &child, style::margins margin, Args&&... args) { - createChildRow(child, margin, std::forward(args)...); - addCreatedRow(child, margin); - return child; + void createChildRow( + Widget *&child, + style::margins margin, + Args&&... args) { + auto row = object_ptr{ nullptr }; + createChildWidget(row, margin, std::forward(args)...); + child = static_cast(addCreatedRow( + std::move(row), + margin)); } private: template - void createChildRow(object_ptr> &child, style::margins &margin, const style::margins &padding, Args&&... args) { + void createChildWidget( + object_ptr> &child, + style::margins &margin, + const style::margins &padding, + Args&&... args) { object_ptr entity = { nullptr }; - createChildRow(entity, margin, std::forward(args)...); - child.create(this, std::move(entity), padding, [this] { rowHeightUpdated(); }); + createChildWidget(entity, margin, std::forward(args)...); + child.create(this, std::move(entity), padding); margin.setLeft(margin.left() - padding.left()); margin.setTop(margin.top() - padding.top()); margin.setRight(margin.right() - padding.right()); margin.setBottom(margin.bottom() - padding.bottom()); } - void createChildRow(object_ptr &child, style::margins &margin, const QString &text, base::lambda callback, bool checked); - void createChildRow(object_ptr &child, style::margins &margin, const QString &text, const char *slot, const style::LinkButton &st = st::boxLinkButton); + void createChildWidget( + object_ptr &child, + style::margins &margin, + const QString &text, base::lambda callback, bool checked); + void createChildWidget( + object_ptr &child, + style::margins &margin, + const QString &text, + const char *slot, + const style::LinkButton &st = st::boxLinkButton); template - void createChildRow(object_ptr> &child, style::margins &margin, const std::shared_ptr> &group, Enum value, const QString &text) { - child.create(this, group, value, text, st::defaultBoxCheckbox); + void createChildWidget( + object_ptr> &child, + style::margins &margin, + const std::shared_ptr> &group, + Enum value, + const QString &text) { + child.create( + this, + group, + value, + text, + st::defaultBoxCheckbox); } - void addCreatedRow(TWidget *child, const style::margins &margin); - void rowHeightUpdated(); + RpWidget *addCreatedRow( + object_ptr row, + const style::margins &margin); template - struct IsWidgetSlideWrap : std::false_type { + struct IsSlideWrap : std::false_type { }; template - struct IsWidgetSlideWrap> : std::true_type { + struct IsSlideWrap> : std::true_type { }; template struct IsRadioenum : std::false_type { @@ -117,23 +142,19 @@ private: template using NotImplementedYet = std::enable_if_t< - !IsWidgetSlideWrap::value && + !IsSlideWrap::value && !IsRadioenum::value && !std::is_same::value && !std::is_same::value>; template > - void createChildRow(object_ptr &child, style::margins &margin, Args&&... args) { + void createChildWidget(object_ptr &child, style::margins &margin, Args&&... args) { child.create(this, std::forward(args)...); } void paintTitle(Painter &p); - struct ChildRow { - TWidget *child; - style::margins margin; - }; - QVector _rows; + object_ptr _content; int _contentLeft = 0; UserData *_self; diff --git a/Telegram/SourceFiles/settings/settings_chat_settings_widget.cpp b/Telegram/SourceFiles/settings/settings_chat_settings_widget.cpp index b6124ba7a..113afbab7 100644 --- a/Telegram/SourceFiles/settings/settings_chat_settings_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_chat_settings_widget.cpp @@ -22,7 +22,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "styles/style_settings.h" #include "lang/lang_keys.h" -#include "ui/effects/widget_slide_wrap.h" +#include "ui/wrap/slide_wrap.h" #include "ui/widgets/checkbox.h" #include "ui/widgets/buttons.h" #include "ui/widgets/labels.h" @@ -36,7 +36,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org namespace Settings { -LabeledLink::LabeledLink(QWidget *parent, const QString &label, const QString &text, Type type, const char *slot) : TWidget(parent) +LabeledLink::LabeledLink(QWidget *parent, const QString &label, const QString &text, Type type, const char *slot) : RpWidget(parent) , _label(this, label, Ui::FlatLabel::InitType::Simple, (type == Type::Primary) ? st::settingsPrimaryLabel : st::defaultFlatLabel) , _link(this, text, (type == Type::Primary) ? st::boxLinkButton : st::defaultLinkButton) { connect(_link, SIGNAL(clicked()), parent, slot); @@ -58,7 +58,7 @@ int LabeledLink::resizeGetHeight(int newWidth) { } #ifndef OS_WIN_STORE -DownloadPathState::DownloadPathState(QWidget *parent) : TWidget(parent) +DownloadPathState::DownloadPathState(QWidget *parent) : RpWidget(parent) , _path(this, lang(lng_download_path_label), downloadPathText(), LabeledLink::Type::Secondary, SLOT(onDownloadPath())) , _clear(this, lang(lng_download_path_clear)) { connect(_clear, SIGNAL(clicked()), this, SLOT(onClear())); @@ -153,32 +153,32 @@ void ChatSettingsWidget::createControls() { style::margins marginSub(0, 0, 0, st::settingsSubSkip); style::margins slidedPadding(0, marginSub.bottom() / 2, 0, marginSub.bottom() - (marginSub.bottom() / 2)); - addChildRow(_replaceEmoji, marginSkip, lang(lng_settings_replace_emojis), [this](bool) { onReplaceEmoji(); }, cReplaceEmojis()); + createChildRow(_replaceEmoji, marginSkip, lang(lng_settings_replace_emojis), [this](bool) { onReplaceEmoji(); }, cReplaceEmojis()); #ifndef OS_WIN_STORE auto pathMargin = marginSub; #else // OS_WIN_STORE auto pathMargin = marginSkip; #endif // OS_WIN_STORE - addChildRow(_dontAskDownloadPath, pathMargin, lang(lng_download_path_dont_ask), [this](bool) { onDontAskDownloadPath(); }, !Global::AskDownloadPath()); + createChildRow(_dontAskDownloadPath, pathMargin, lang(lng_download_path_dont_ask), [this](bool) { onDontAskDownloadPath(); }, !Global::AskDownloadPath()); #ifndef OS_WIN_STORE style::margins marginPath(st::defaultCheck.diameter + st::defaultBoxCheckbox.textPosition.x(), 0, 0, st::settingsSkip); - addChildRow(_downloadPath, marginPath, slidedPadding); + createChildRow(_downloadPath, marginPath, slidedPadding); if (Global::AskDownloadPath()) { _downloadPath->hideFast(); } #endif // OS_WIN_STORE auto group = std::make_shared>(cCtrlEnter() ? SendByType::CtrlEnter : SendByType::Enter); - addChildRow(_sendByEnter, marginSmall, group, SendByType::Enter, lang(lng_settings_send_enter)); - addChildRow(_sendByCtrlEnter, marginSkip, group, SendByType::CtrlEnter, lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_settings_send_cmdenter : lng_settings_send_ctrlenter)); + createChildRow(_sendByEnter, marginSmall, group, SendByType::Enter, lang(lng_settings_send_enter)); + createChildRow(_sendByCtrlEnter, marginSkip, group, SendByType::CtrlEnter, lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_settings_send_cmdenter : lng_settings_send_ctrlenter)); group->setChangedCallback([this](SendByType value) { sendByChanged(value); }); - addChildRow(_automaticMediaDownloadSettings, marginSmall, lang(lng_media_auto_settings), SLOT(onAutomaticMediaDownloadSettings())); - addChildRow(_manageStickerSets, marginSmall, lang(lng_stickers_you_have), SLOT(onManageStickerSets())); + createChildRow(_automaticMediaDownloadSettings, marginSmall, lang(lng_media_auto_settings), SLOT(onAutomaticMediaDownloadSettings())); + createChildRow(_manageStickerSets, marginSmall, lang(lng_stickers_you_have), SLOT(onManageStickerSets())); } void ChatSettingsWidget::onReplaceEmoji() { diff --git a/Telegram/SourceFiles/settings/settings_chat_settings_widget.h b/Telegram/SourceFiles/settings/settings_chat_settings_widget.h index 6357e0b27..9016d3d22 100644 --- a/Telegram/SourceFiles/settings/settings_chat_settings_widget.h +++ b/Telegram/SourceFiles/settings/settings_chat_settings_widget.h @@ -21,6 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #pragma once #include "settings/settings_block_widget.h" +#include "ui/rp_widget.h" namespace Ui { class FlatLabel; @@ -28,7 +29,7 @@ class FlatLabel; namespace Settings { -class LabeledLink : public TWidget { +class LabeledLink : public Ui::RpWidget { public: enum class Type { Primary, @@ -50,7 +51,7 @@ private: }; #ifndef OS_WIN_STORE -class DownloadPathState : public TWidget, private base::Subscriber { +class DownloadPathState : public Ui::RpWidget, private base::Subscriber { Q_OBJECT public: @@ -106,17 +107,17 @@ private: void sendByChanged(SendByType value); void createControls(); - object_ptr _replaceEmoji = { nullptr }; - object_ptr _dontAskDownloadPath = { nullptr }; + Ui::Checkbox *_replaceEmoji = nullptr; + Ui::Checkbox *_dontAskDownloadPath = nullptr; #ifndef OS_WIN_STORE - object_ptr> _downloadPath = { nullptr }; + Ui::SlideWrap *_downloadPath = nullptr; #endif // OS_WIN_STORE - object_ptr> _sendByEnter = { nullptr }; - object_ptr> _sendByCtrlEnter = { nullptr }; - object_ptr _automaticMediaDownloadSettings = { nullptr }; - object_ptr _manageStickerSets = { nullptr }; + Ui::Radioenum *_sendByEnter = nullptr; + Ui::Radioenum *_sendByCtrlEnter = nullptr; + Ui::LinkButton *_automaticMediaDownloadSettings = nullptr; + Ui::LinkButton *_manageStickerSets = nullptr; }; diff --git a/Telegram/SourceFiles/settings/settings_cover.cpp b/Telegram/SourceFiles/settings/settings_cover.cpp index e6f7c855d..4b1642bfc 100644 --- a/Telegram/SourceFiles/settings/settings_cover.cpp +++ b/Telegram/SourceFiles/settings/settings_cover.cpp @@ -101,12 +101,22 @@ int CoverWidget::resizeGetHeight(int newWidth) { newHeight += st::settingsMarginTop; - _userpicButton->moveToLeft(contentLeft() + st::settingsPhotoLeft, newHeight, newWidth); + auto margins = getMargins(); + _userpicButton->moveToLeft( + margins.left() + contentLeft() + st::settingsPhotoLeft, + margins.top() + newHeight, + newWidth); int infoLeft = _userpicButton->x() + _userpicButton->width(); _statusPosition = QPoint(infoLeft + st::settingsStatusLeft, _userpicButton->y() + st::settingsStatusTop); if (_cancelPhotoUpload) { - _cancelPhotoUpload->moveToLeft(_statusPosition.x() + st::settingsStatusFont->width(_statusText) + st::settingsStatusFont->spacew, _statusPosition.y(), newWidth); + _cancelPhotoUpload->moveToLeft( + margins.left() + + _statusPosition.x() + + st::settingsStatusFont->width(_statusText) + + st::settingsStatusFont->spacew, + margins.top() + _statusPosition.y(), + newWidth); } refreshButtonsGeometry(newWidth); @@ -125,20 +135,27 @@ int CoverWidget::resizeGetHeight(int newWidth) { } void CoverWidget::refreshButtonsGeometry(int newWidth) { - int buttonLeft = _userpicButton->x() + _userpicButton->width() + st::settingsButtonLeft; - int buttonsRight = newWidth - st::settingsButtonSkip; - _setPhoto->moveToLeft(buttonLeft, _userpicButton->y() + st::settingsButtonTop, newWidth); + auto margins = getMargins(); + auto buttonLeft = margins.left() + _userpicButton->x() + _userpicButton->width() + st::settingsButtonLeft; + _setPhoto->moveToLeft( + buttonLeft, + margins.top() + _userpicButton->y() + st::settingsButtonTop, + newWidth); buttonLeft += _setPhoto->width() + st::settingsButtonSkip; - _editName->moveToLeft(buttonLeft, _setPhoto->y(), newWidth); + _editName->moveToLeft( + buttonLeft, + margins.top() + _setPhoto->y(), + newWidth); _editNameVisible = (buttonLeft + _editName->width() + st::settingsButtonSkip <= newWidth); _editName->setVisible(_editNameVisible); } void CoverWidget::refreshNameGeometry(int newWidth) { - int infoLeft = _userpicButton->x() + _userpicButton->width(); - int nameLeft = infoLeft + st::settingsNameLeft - st::settingsNameLabel.margin.left(); - int nameTop = _userpicButton->y() + st::settingsNameTop - st::settingsNameLabel.margin.top(); - int nameWidth = newWidth - infoLeft - st::settingsNameLeft; + auto margins = getMargins(); + auto infoLeft = _userpicButton->x() + _userpicButton->width(); + auto nameLeft = infoLeft + st::settingsNameLeft - st::settingsNameLabel.margin.left(); + auto nameTop = _userpicButton->y() + st::settingsNameTop - st::settingsNameLabel.margin.top(); + auto nameWidth = newWidth - infoLeft - st::settingsNameLeft; auto editNameInlineVisible = !_editNameVisible; if (editNameInlineVisible) { nameWidth -= _editNameInline->width(); @@ -146,9 +163,15 @@ void CoverWidget::refreshNameGeometry(int newWidth) { int marginsAdd = st::settingsNameLabel.margin.left() + st::settingsNameLabel.margin.right(); _name->resizeToWidth(qMin(nameWidth - marginsAdd, _name->naturalWidth()) + marginsAdd); - _name->moveToLeft(nameLeft, nameTop, newWidth); + _name->moveToLeft( + margins.left() + nameLeft, + margins.top() + nameTop, + newWidth); - _editNameInline->moveToLeft(nameLeft + _name->width(), nameTop, newWidth); + _editNameInline->moveToLeft( + margins.left() + nameLeft + _name->width(), + margins.top() + nameTop, + newWidth); _editNameInline->setVisible(editNameInlineVisible); } @@ -283,10 +306,16 @@ void CoverWidget::refreshStatusText() { _statusText = lang(lng_settings_uploading_photo); _statusTextIsOnline = false; if (!_cancelPhotoUpload) { + auto margins = getMargins(); _cancelPhotoUpload.create(this, lang(lng_cancel), st::defaultLinkButton); connect(_cancelPhotoUpload, SIGNAL(clicked()), this, SLOT(onCancelPhotoUpload())); _cancelPhotoUpload->show(); - _cancelPhotoUpload->moveToLeft(_statusPosition.x() + st::settingsStatusFont->width(_statusText) + st::settingsStatusFont->spacew, _statusPosition.y()); + _cancelPhotoUpload->moveToLeft( + margins.left() + + _statusPosition.x() + + st::settingsStatusFont->width(_statusText) + + st::settingsStatusFont->spacew, + margins.top() + _statusPosition.y()); } update(); return; diff --git a/Telegram/SourceFiles/settings/settings_general_widget.cpp b/Telegram/SourceFiles/settings/settings_general_widget.cpp index 38fe46a1b..862752504 100644 --- a/Telegram/SourceFiles/settings/settings_general_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_general_widget.cpp @@ -22,7 +22,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "styles/style_settings.h" #include "lang/lang_keys.h" -#include "ui/effects/widget_slide_wrap.h" +#include "ui/wrap/slide_wrap.h" #include "ui/widgets/checkbox.h" #include "ui/widgets/buttons.h" #include "storage/localstorage.h" @@ -41,7 +41,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org namespace Settings { #ifndef TDESKTOP_DISABLE_AUTOUPDATE -UpdateStateRow::UpdateStateRow(QWidget *parent) : TWidget(parent) +UpdateStateRow::UpdateStateRow(QWidget *parent) : RpWidget(parent) , _check(this, lang(lng_settings_check_now)) , _restart(this, lang(lng_settings_update_now)) { connect(_check, SIGNAL(clicked()), this, SLOT(onCheck())); @@ -164,7 +164,7 @@ GeneralWidget::GeneralWidget(QWidget *parent, UserData *self) : BlockWidget(pare } int GeneralWidget::resizeGetHeight(int newWidth) { - _changeLanguage->moveToRight(contentLeft(), st::settingsBlockMarginTop + st::settingsBlockTitleTop + st::settingsBlockTitleFont->ascent - st::defaultLinkButton.font->ascent, newWidth); + _changeLanguage->moveToRight(0, st::settingsBlockMarginTop + st::settingsBlockTitleTop + st::settingsBlockTitleFont->ascent - st::defaultLinkButton.font->ascent, newWidth); return BlockWidget::resizeGetHeight(newWidth); } @@ -175,9 +175,9 @@ void GeneralWidget::refreshControls() { style::margins slidedPadding(0, marginSmall.bottom() / 2, 0, marginSmall.bottom() - (marginSmall.bottom() / 2)); #ifndef TDESKTOP_DISABLE_AUTOUPDATE - addChildRow(_updateAutomatically, marginSub, lang(lng_settings_update_automatically), [this](bool) { onUpdateAutomatically(); }, cAutoUpdate()); + createChildRow(_updateAutomatically, marginSub, lang(lng_settings_update_automatically), [this](bool) { onUpdateAutomatically(); }, cAutoUpdate()); style::margins marginLink(st::defaultCheck.diameter + st::defaultBoxCheckbox.textPosition.x(), 0, 0, st::settingsSkip); - addChildRow(_updateRow, marginLink, slidedPadding); + createChildRow(_updateRow, marginLink, slidedPadding); connect(_updateRow->entity(), SIGNAL(restart()), this, SLOT(onRestart())); if (!cAutoUpdate()) { _updateRow->hideFast(); @@ -186,20 +186,20 @@ void GeneralWidget::refreshControls() { if (cPlatform() == dbipWindows || cSupportTray()) { auto workMode = Global::WorkMode().value(); - addChildRow(_enableTrayIcon, marginSmall, lang(lng_settings_workmode_tray), [this](bool) { onEnableTrayIcon(); }, (workMode == dbiwmTrayOnly || workMode == dbiwmWindowAndTray)); + createChildRow(_enableTrayIcon, marginSmall, lang(lng_settings_workmode_tray), [this](bool) { onEnableTrayIcon(); }, (workMode == dbiwmTrayOnly || workMode == dbiwmWindowAndTray)); if (cPlatform() == dbipWindows) { - addChildRow(_enableTaskbarIcon, marginLarge, lang(lng_settings_workmode_window), [this](bool) { onEnableTaskbarIcon(); }, (workMode == dbiwmWindowOnly || workMode == dbiwmWindowAndTray)); + createChildRow(_enableTaskbarIcon, marginLarge, lang(lng_settings_workmode_window), [this](bool) { onEnableTaskbarIcon(); }, (workMode == dbiwmWindowOnly || workMode == dbiwmWindowAndTray)); #ifndef OS_WIN_STORE - addChildRow(_autoStart, marginSmall, lang(lng_settings_auto_start), [this](bool) { onAutoStart(); }, cAutoStart()); - addChildRow(_startMinimized, marginLarge, slidedPadding, lang(lng_settings_start_min), [this](bool) { onStartMinimized(); }, (cStartMinimized() && !Global::LocalPasscode())); + createChildRow(_autoStart, marginSmall, lang(lng_settings_auto_start), [this](bool) { onAutoStart(); }, cAutoStart()); + createChildRow(_startMinimized, marginLarge, slidedPadding, lang(lng_settings_start_min), [this](bool) { onStartMinimized(); }, (cStartMinimized() && !Global::LocalPasscode())); subscribe(Global::RefLocalPasscodeChanged(), [this] { _startMinimized->entity()->setChecked(cStartMinimized() && !Global::LocalPasscode()); }); if (!cAutoStart()) { _startMinimized->hideFast(); } - addChildRow(_addInSendTo, marginSmall, lang(lng_settings_add_sendto), [this](bool) { onAddInSendTo(); }, cSendToMenu()); + createChildRow(_addInSendTo, marginSmall, lang(lng_settings_add_sendto), [this](bool) { onAddInSendTo(); }, cSendToMenu()); #endif // OS_WIN_STORE } } diff --git a/Telegram/SourceFiles/settings/settings_general_widget.h b/Telegram/SourceFiles/settings/settings_general_widget.h index 71f2260a1..c1df09418 100644 --- a/Telegram/SourceFiles/settings/settings_general_widget.h +++ b/Telegram/SourceFiles/settings/settings_general_widget.h @@ -21,11 +21,12 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #pragma once #include "settings/settings_block_widget.h" +#include "ui/rp_widget.h" namespace Settings { #ifndef TDESKTOP_DISABLE_AUTOUPDATE -class UpdateStateRow : public TWidget { +class UpdateStateRow : public Ui::RpWidget { Q_OBJECT public: @@ -107,14 +108,14 @@ private: object_ptr _changeLanguage; #ifndef TDESKTOP_DISABLE_AUTOUPDATE - object_ptr _updateAutomatically = { nullptr }; - object_ptr> _updateRow = { nullptr }; + Ui::Checkbox *_updateAutomatically = nullptr; + Ui::SlideWrap *_updateRow = nullptr; #endif // !TDESKTOP_DISABLE_AUTOUPDATE - object_ptr _enableTrayIcon = { nullptr }; - object_ptr _enableTaskbarIcon = { nullptr }; - object_ptr _autoStart = { nullptr }; - object_ptr> _startMinimized = { nullptr }; - object_ptr _addInSendTo = { nullptr }; + Ui::Checkbox *_enableTrayIcon = nullptr; + Ui::Checkbox *_enableTaskbarIcon = nullptr; + Ui::Checkbox *_autoStart = nullptr; + Ui::SlideWrap *_startMinimized = nullptr; + Ui::Checkbox *_addInSendTo = nullptr; int _languagesLoadedSubscription = 0; diff --git a/Telegram/SourceFiles/settings/settings_info_widget.cpp b/Telegram/SourceFiles/settings/settings_info_widget.cpp index 086ceabde..489d387ba 100644 --- a/Telegram/SourceFiles/settings/settings_info_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_info_widget.cpp @@ -23,7 +23,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "styles/style_settings.h" #include "lang/lang_keys.h" #include "ui/widgets/labels.h" -#include "ui/effects/widget_slide_wrap.h" +#include "ui/wrap/slide_wrap.h" #include "boxes/username_box.h" #include "boxes/add_contact_box.h" #include "boxes/change_phone_box.h" @@ -46,9 +46,9 @@ InfoWidget::InfoWidget(QWidget *parent, UserData *self) : BlockWidget(parent, se void InfoWidget::createControls() { style::margins margin(0, 0, 0, 0); style::margins slidedPadding(0, 0, 0, 0); - addChildRow(_mobileNumber, margin, slidedPadding, st::settingsBlockOneLineTextPart); - addChildRow(_username, margin, slidedPadding, st::settingsBlockOneLineTextPart); - addChildRow(_bio, margin, slidedPadding, st::settingsBioValue); + createChildRow(_mobileNumber, margin, slidedPadding, st::settingsBlockOneLineTextPart); + createChildRow(_username, margin, slidedPadding, st::settingsBlockOneLineTextPart); + createChildRow(_bio, margin, slidedPadding, st::settingsBioValue); refreshControls(); } @@ -67,7 +67,12 @@ void InfoWidget::refreshMobileNumber() { phoneText.text = App::phoneFromSharedContact(peerToUser(user->id)); } } - setLabeledText(_mobileNumber, lang(lng_profile_mobile_number), phoneText, TextWithEntities(), lang(lng_profile_copy_phone)); + setLabeledText( + _mobileNumber, + lang(lng_profile_mobile_number), + phoneText, + TextWithEntities(), + lang(lng_profile_copy_phone)); if (auto text = _mobileNumber->entity()->textLabel()) { text->setRichText(textcmdLink(1, phoneText.text)); text->setLink(1, MakeShared([] { @@ -86,7 +91,12 @@ void InfoWidget::refreshUsername() { copyText = lang(lng_context_copy_mention); } usernameText.entities.push_back(EntityInText(EntityInTextCustomUrl, 0, usernameText.text.size(), Messenger::Instance().createInternalLinkFull(self()->username))); - setLabeledText(_username, lang(lng_profile_username), usernameText, TextWithEntities(), copyText); + setLabeledText( + _username, + lang(lng_profile_username), + usernameText, + TextWithEntities(), + copyText); if (auto text = _username->entity()->textLabel()) { text->setClickHandlerHook([](const ClickHandlerPtr &handler, Qt::MouseButton button) { Ui::show(Box()); @@ -104,7 +114,12 @@ void InfoWidget::refreshBio() { bioText.text = aboutText; } bioText.entities.push_back(EntityInText(EntityInTextCustomUrl, 0, bioText.text.size(), QString())); - setLabeledText(_bio, lang(lng_profile_bio), bioText, TextWithEntities(), QString()); + setLabeledText( + _bio, + lang(lng_profile_bio), + bioText, + TextWithEntities(), + QString()); if (auto text = _bio->entity()->textLabel()) { text->setClickHandlerHook([](const ClickHandlerPtr &handler, Qt::MouseButton button) { Ui::show(Box(App::self())); @@ -113,19 +128,34 @@ void InfoWidget::refreshBio() { } } -void InfoWidget::setLabeledText(object_ptr &row, const QString &label, const TextWithEntities &textWithEntities, const TextWithEntities &shortTextWithEntities, const QString ©Text) { +void InfoWidget::setLabeledText( + LabeledWrap *row, + const QString &label, + const TextWithEntities &textWithEntities, + const TextWithEntities &shortTextWithEntities, + const QString ©Text) { auto nonEmptyText = !textWithEntities.text.isEmpty(); if (nonEmptyText) { - row->entity()->setLabeledText(label, textWithEntities, shortTextWithEntities, copyText); + row->entity()->setLabeledText( + label, + textWithEntities, + shortTextWithEntities, + copyText, + width()); } row->toggleAnimated(nonEmptyText); } -InfoWidget::LabeledWidget::LabeledWidget(QWidget *parent, const style::FlatLabel &valueSt) : TWidget(parent) +InfoWidget::LabeledWidget::LabeledWidget(QWidget *parent, const style::FlatLabel &valueSt) : RpWidget(parent) , _valueSt(valueSt) { } -void InfoWidget::LabeledWidget::setLabeledText(const QString &label, const TextWithEntities &textWithEntities, const TextWithEntities &shortTextWithEntities, const QString ©Text) { +void InfoWidget::LabeledWidget::setLabeledText( + const QString &label, + const TextWithEntities &textWithEntities, + const TextWithEntities &shortTextWithEntities, + const QString ©Text, + int availableWidth) { _label.destroy(); _text.destroy(); _shortText.destroy(); @@ -135,7 +165,7 @@ void InfoWidget::LabeledWidget::setLabeledText(const QString &label, const TextW _label->show(); setLabelText(_text, textWithEntities, copyText); setLabelText(_shortText, shortTextWithEntities, copyText); - resizeToWidth(width()); + resizeToNaturalWidth(availableWidth); } Ui::FlatLabel *InfoWidget::LabeledWidget::textLabel() const { @@ -172,8 +202,6 @@ void InfoWidget::notifyPeerUpdated(const Notify::PeerUpdate &update) { if (update.flags & UpdateFlag::AboutChanged) { refreshBio(); } - - contentSizeUpdated(); } int InfoWidget::LabeledWidget::naturalWidth() const { @@ -188,10 +216,7 @@ int InfoWidget::LabeledWidget::resizeGetHeight(int newWidth) { if (!_label) return 0; _label->moveToLeft(0, st::settingsBlockOneLineTextPart.margin.top(), newWidth); - auto labelNatural = _label->naturalWidth(); - Assert(labelNatural >= 0); - - _label->resize(qMin(newWidth, labelNatural), _label->height()); + _label->resizeToNaturalWidth(newWidth); int textLeft = _label->width() + st::normalFont->spacew; int textWidth = _text->naturalWidth(); diff --git a/Telegram/SourceFiles/settings/settings_info_widget.h b/Telegram/SourceFiles/settings/settings_info_widget.h index 2c33898e9..71efa3800 100644 --- a/Telegram/SourceFiles/settings/settings_info_widget.h +++ b/Telegram/SourceFiles/settings/settings_info_widget.h @@ -21,6 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #pragma once #include "settings/settings_block_widget.h" +#include "ui/rp_widget.h" namespace Ui { class FlatLabel; @@ -46,11 +47,16 @@ private: void refreshUsername(); void refreshBio(); - class LabeledWidget : public TWidget { + class LabeledWidget : public Ui::RpWidget { public: LabeledWidget(QWidget *parent, const style::FlatLabel &valueSt); - void setLabeledText(const QString &label, const TextWithEntities &textWithEntities, const TextWithEntities &shortTextWithEntities, const QString ©Text); + void setLabeledText( + const QString &label, + const TextWithEntities &textWithEntities, + const TextWithEntities &shortTextWithEntities, + const QString ©Text, + int availableWidth); Ui::FlatLabel *textLabel() const; Ui::FlatLabel *shortTextLabel() const; @@ -61,7 +67,10 @@ private: int resizeGetHeight(int newWidth) override; private: - void setLabelText(object_ptr &text, const TextWithEntities &textWithEntities, const QString ©Text); + void setLabelText( + object_ptr &text, + const TextWithEntities &textWithEntities, + const QString ©Text); const style::FlatLabel &_valueSt; object_ptr _label = { nullptr }; @@ -70,12 +79,17 @@ private: }; - using LabeledWrap = Ui::WidgetSlideWrap; - void setLabeledText(object_ptr &row, const QString &label, const TextWithEntities &textWithEntities, const TextWithEntities &shortTextWithEntities, const QString ©Text); + using LabeledWrap = Ui::SlideWrap; + void setLabeledText( + LabeledWrap *row, + const QString &label, + const TextWithEntities &textWithEntities, + const TextWithEntities &shortTextWithEntities, + const QString ©Text); - object_ptr _mobileNumber = { nullptr }; - object_ptr _username = { nullptr }; - object_ptr _bio = { nullptr }; + LabeledWrap *_mobileNumber = nullptr; + LabeledWrap *_username = nullptr; + LabeledWrap *_bio = nullptr; }; diff --git a/Telegram/SourceFiles/settings/settings_inner_widget.cpp b/Telegram/SourceFiles/settings/settings_inner_widget.cpp index 7a3d7f3f2..bc529ad4c 100644 --- a/Telegram/SourceFiles/settings/settings_inner_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_inner_widget.cpp @@ -36,7 +36,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org namespace Settings { InnerWidget::InnerWidget(QWidget *parent) : LayerInner(parent) -, _self(App::self()) { +, _self(App::self()) +, _blocks(this) { refreshBlocks(); subscribe(Global::RefSelfChanged(), [this] { fullRebuild(); }); subscribe(Lang::Current().updated(), [this] { fullRebuild(); }); @@ -45,44 +46,34 @@ InnerWidget::InnerWidget(QWidget *parent) : LayerInner(parent) void InnerWidget::fullRebuild() { _self = App::self(); refreshBlocks(); - - if (_cover) { - _cover->setContentLeft(_contentLeft); - _cover->resizeToWidth(width()); - } - for_const (auto block, _blocks) { - block->setContentLeft(_contentLeft); - block->resizeToWidth(width()); - } - onBlockHeightUpdated(); } void InnerWidget::refreshBlocks() { - _cover.destroyDelayed(); - for_const (auto block, _blocks) { - block->hide(); - block->deleteLater(); - } - _blocks.clear(); - if (App::quitting()) { + _cover.destroy(); + _blocks.destroy(); return; } + _cover = _self + ? object_ptr(this, _self) + : nullptr; + _blocks = object_ptr(this); + resizeToWidth(width(), _contentLeft); + if (_self) { - _cover.create(this, _self); - _blocks.push_back(new InfoWidget(this, _self)); - _blocks.push_back(new NotificationsWidget(this, _self)); + _blocks->add(object_ptr(this, _self)); + _blocks->add(object_ptr(this, _self)); } - _blocks.push_back(new GeneralWidget(this, _self)); + _blocks->add(object_ptr(this, _self)); if (!cRetina()) { - _blocks.push_back(new ScaleWidget(this, _self)); + _blocks->add(object_ptr(this, _self)); } if (_self) { - _blocks.push_back(new ChatSettingsWidget(this, _self)); - _blocks.push_back(new BackgroundWidget(this, _self)); - _blocks.push_back(new PrivacyWidget(this, _self)); + _blocks->add(object_ptr(this, _self)); + _blocks->add(object_ptr(this, _self)); + _blocks->add(object_ptr(this, _self)); } - _blocks.push_back(new AdvancedWidget(this, _self)); + _blocks->add(object_ptr(this, _self)); if (_cover) { _cover->show(); @@ -90,10 +81,12 @@ void InnerWidget::refreshBlocks() { _cover->showFinished(); } } - for_const (auto block, _blocks) { - block->show(); - connect(block, SIGNAL(heightUpdated()), this, SLOT(onBlockHeightUpdated())); - } + _blocks->show(); + _blocks->heightValue() + | rpl::on_next([this](int blocksHeight) { + resize(width(), _blocks->y() + blocksHeight); + }) + | rpl::start(lifetime()); } void InnerWidget::showFinished() { @@ -108,44 +101,25 @@ int InnerWidget::resizeGetHeight(int newWidth) { _cover->setContentLeft(_contentLeft); _cover->resizeToWidth(newWidth); } - for_const (auto block, _blocks) { - block->setContentLeft(_contentLeft); - block->resizeToWidth(newWidth); - } - - int result = refreshBlocksPositions(newWidth); - return result; + _blocks->resizeToWidth(newWidth - 2 * _contentLeft); + _blocks->moveToLeft( + _contentLeft, + (_cover ? (_cover->y() + _cover->height()) : 0) + + st::settingsBlocksTop); + return height(); } -int InnerWidget::refreshBlocksPositions(int newWidth) { - int result = (_cover ? _cover->height() : 0) + st::settingsBlocksTop; - for_const (auto block, _blocks) { - if (block->isHidden()) { - continue; - } - - block->moveToLeft(0, result, newWidth); - result += block->height(); - } - return result; -} - -void InnerWidget::onBlockHeightUpdated() { - int newHeight = refreshBlocksPositions(width()); - if (newHeight != height()) { - resize(width(), newHeight); - emit heightUpdated(); - } -} - -void InnerWidget::setVisibleTopBottom(int visibleTop, int visibleBottom) { - _visibleTop = visibleTop; - _visibleBottom = visibleBottom; - - for_const (auto block, _blocks) { - int blockY = block->y(); - block->setVisibleTopBottom(visibleTop - blockY, visibleBottom - blockY); - } +void InnerWidget::visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) { + setChildVisibleTopBottom( + _cover, + visibleTop, + visibleBottom); + setChildVisibleTopBottom( + _blocks, + visibleTop, + visibleBottom); } } // namespace Settings diff --git a/Telegram/SourceFiles/settings/settings_inner_widget.h b/Telegram/SourceFiles/settings/settings_inner_widget.h index e61dd1258..9a0914226 100644 --- a/Telegram/SourceFiles/settings/settings_inner_widget.h +++ b/Telegram/SourceFiles/settings/settings_inner_widget.h @@ -21,6 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #pragma once #include "settings/settings_layer.h" +#include "ui/wrap/vertical_layout.h" namespace Settings { @@ -28,8 +29,6 @@ class CoverWidget; class BlockWidget; class InnerWidget : public LayerInner, private base::Subscriber { - Q_OBJECT - public: InnerWidget(QWidget *parent); @@ -39,36 +38,26 @@ public: return TWidget::resizeToWidth(newWidth); } - // Updates the area that is visible inside the scroll container. - void setVisibleTopBottom(int visibleTop, int visibleBottom) override; - void showFinished(); -private slots: - void onBlockHeightUpdated(); - protected: - // Resizes content and counts natural widget height for the desired width. int resizeGetHeight(int newWidth) override; + void visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) override; private: void fullRebuild(); void refreshBlocks(); - // Returns the new height value. - int refreshBlocksPositions(int newWidth); - object_ptr _cover = { nullptr }; - QList _blocks; + object_ptr _blocks; UserData *_self = nullptr; int _contentLeft = 0; bool _showFinished = false; - int _visibleTop = 0; - int _visibleBottom = 0; - }; } // namespace Settings diff --git a/Telegram/SourceFiles/settings/settings_layer.cpp b/Telegram/SourceFiles/settings/settings_layer.cpp index 46b2b4635..12bfd1c14 100644 --- a/Telegram/SourceFiles/settings/settings_layer.cpp +++ b/Telegram/SourceFiles/settings/settings_layer.cpp @@ -50,21 +50,19 @@ Layer::Layer() _fixedBarShadow->hideFast(); _scroll->moveToLeft(0, st::settingsFixedBarHeight); - connect(_scroll, SIGNAL(scrolled()), this, SLOT(onScroll())); + _scroll->scrollTopValue() + | rpl::map([](int scrollTop) { return scrollTop > 0; }) + | rpl::distinct_until_changed() + | rpl::on_next([this](bool scrolled) { + _fixedBarShadow->toggleAnimated(scrolled); + }) + | rpl::start(lifetime()); } void Layer::setCloseClickHandler(base::lambda callback) { _fixedBarClose->setClickedCallback(std::move(callback)); } -void Layer::onScroll() { - if (_scroll->scrollTop() > 0) { - _fixedBarShadow->showAnimated(); - } else { - _fixedBarShadow->hideAnimated(); - } -} - void Layer::resizeToWidth(int newWidth, int newContentLeft) { // Widget height depends on InnerWidget height, so we // resize it here, not in the resizeEvent() handler. @@ -73,13 +71,13 @@ void Layer::resizeToWidth(int newWidth, int newContentLeft) { resizeUsingInnerHeight(newWidth, _inner->height()); } -void Layer::onInnerHeightUpdated() { - resizeUsingInnerHeight(width(), _inner->height()); -} - void Layer::doSetInnerWidget(object_ptr widget) { _inner = _scroll->setOwnedWidget(std::move(widget)); - connect(_inner, SIGNAL(heightUpdated()), this, SLOT(onInnerHeightUpdated())); + _inner->heightValue() + | rpl::on_next([this](int innerHeight) { + resizeUsingInnerHeight(width(), innerHeight); + }) + | rpl::start(lifetime()); } void Layer::paintEvent(QPaintEvent *e) { diff --git a/Telegram/SourceFiles/settings/settings_layer.h b/Telegram/SourceFiles/settings/settings_layer.h index 7a36a1406..fbc3b313e 100644 --- a/Telegram/SourceFiles/settings/settings_layer.h +++ b/Telegram/SourceFiles/settings/settings_layer.h @@ -21,6 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #pragma once #include "layerwidget.h" +#include "ui/rp_widget.h" class BoxLayerTitleShadow; @@ -34,9 +35,9 @@ class WidgetFadeWrap; namespace Settings { class FixedBar; -class LayerInner : public TWidget { +class LayerInner : public Ui::RpWidget { public: - LayerInner(QWidget *parent) : TWidget(parent) { + LayerInner(QWidget *parent) : RpWidget(parent) { } virtual void resizeToWidth(int newWidth, int contentLeft) { @@ -46,8 +47,6 @@ public: }; class Layer : public LayerWidget { - Q_OBJECT - public: Layer(); @@ -70,10 +69,6 @@ protected: _roundedCorners = roundedCorners; } -private slots: - void onInnerHeightUpdated(); - void onScroll(); - private: void doSetInnerWidget(object_ptr widget); diff --git a/Telegram/SourceFiles/settings/settings_notifications_widget.cpp b/Telegram/SourceFiles/settings/settings_notifications_widget.cpp index 3c25df36e..e8fa5256e 100644 --- a/Telegram/SourceFiles/settings/settings_notifications_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_notifications_widget.cpp @@ -23,7 +23,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "styles/style_settings.h" #include "lang/lang_keys.h" #include "storage/localstorage.h" -#include "ui/effects/widget_slide_wrap.h" +#include "ui/wrap/slide_wrap.h" #include "ui/widgets/checkbox.h" #include "ui/widgets/buttons.h" #include "mainwindow.h" @@ -56,9 +56,9 @@ NotificationsWidget::NotificationsWidget(QWidget *parent, UserData *self) : Bloc void NotificationsWidget::createControls() { style::margins margin(0, 0, 0, st::settingsSkip); style::margins slidedPadding(0, margin.bottom() / 2, 0, margin.bottom() - (margin.bottom() / 2)); - addChildRow(_desktopNotifications, margin, lang(lng_settings_desktop_notify), [this](bool) { onDesktopNotifications(); }, Global::DesktopNotify()); - addChildRow(_showSenderName, margin, slidedPadding, lang(lng_settings_show_name), [this](bool) { onShowSenderName(); }, Global::NotifyView() <= dbinvShowName); - addChildRow(_showMessagePreview, margin, slidedPadding, lang(lng_settings_show_preview), [this](bool) { onShowMessagePreview(); }, Global::NotifyView() <= dbinvShowPreview); + createChildRow(_desktopNotifications, margin, lang(lng_settings_desktop_notify), [this](bool) { onDesktopNotifications(); }, Global::DesktopNotify()); + createChildRow(_showSenderName, margin, slidedPadding, lang(lng_settings_show_name), [this](bool) { onShowSenderName(); }, Global::NotifyView() <= dbinvShowName); + createChildRow(_showMessagePreview, margin, slidedPadding, lang(lng_settings_show_preview), [this](bool) { onShowMessagePreview(); }, Global::NotifyView() <= dbinvShowPreview); if (!_showSenderName->entity()->checked()) { _showMessagePreview->hideFast(); } @@ -66,8 +66,8 @@ void NotificationsWidget::createControls() { _showSenderName->hideFast(); _showMessagePreview->hideFast(); } - addChildRow(_playSound, margin, lang(lng_settings_sound_notify), [this](bool) { onPlaySound(); }, Global::SoundNotify()); - addChildRow(_includeMuted, margin, lang(lng_settings_include_muted), [this](bool) { onIncludeMuted(); }, Global::IncludeMuted()); + createChildRow(_playSound, margin, lang(lng_settings_sound_notify), [this](bool) { onPlaySound(); }, Global::SoundNotify()); + createChildRow(_includeMuted, margin, lang(lng_settings_include_muted), [this](bool) { onIncludeMuted(); }, Global::IncludeMuted()); if (cPlatform() != dbipMac) { createNotificationsControls(); @@ -87,9 +87,9 @@ void NotificationsWidget::createNotificationsControls() { #endif // Q_OS_WIN || Q_OS_LINUX64 || Q_OS_LINUX32 } if (!nativeNotificationsLabel.isEmpty()) { - addChildRow(_nativeNotifications, margin, nativeNotificationsLabel, [this](bool) { onNativeNotifications(); }, Global::NativeNotifications()); + createChildRow(_nativeNotifications, margin, nativeNotificationsLabel, [this](bool) { onNativeNotifications(); }, Global::NativeNotifications()); } - addChildRow(_advanced, margin, slidedPadding, lang(lng_settings_advanced_notifications), SLOT(onAdvanced())); + createChildRow(_advanced, margin, slidedPadding, lang(lng_settings_advanced_notifications), SLOT(onAdvanced())); if (!nativeNotificationsLabel.isEmpty() && Global::NativeNotifications()) { _advanced->hideFast(); } diff --git a/Telegram/SourceFiles/settings/settings_notifications_widget.h b/Telegram/SourceFiles/settings/settings_notifications_widget.h index 70e01f4b6..b58bf0eec 100644 --- a/Telegram/SourceFiles/settings/settings_notifications_widget.h +++ b/Telegram/SourceFiles/settings/settings_notifications_widget.h @@ -45,13 +45,13 @@ private: void desktopEnabledUpdated(); void viewParamUpdated(); - object_ptr _desktopNotifications = { nullptr }; - object_ptr> _showSenderName = { nullptr }; - object_ptr> _showMessagePreview = { nullptr }; - object_ptr _nativeNotifications = { nullptr }; - object_ptr _playSound = { nullptr }; - object_ptr _includeMuted = { nullptr }; - object_ptr> _advanced = { nullptr }; + Ui::Checkbox *_desktopNotifications = nullptr; + Ui::SlideWrap *_showSenderName = nullptr; + Ui::SlideWrap *_showMessagePreview = nullptr; + Ui::Checkbox *_nativeNotifications = nullptr; + Ui::Checkbox *_playSound = nullptr; + Ui::Checkbox *_includeMuted = nullptr; + Ui::SlideWrap *_advanced = nullptr; }; diff --git a/Telegram/SourceFiles/settings/settings_privacy_widget.cpp b/Telegram/SourceFiles/settings/settings_privacy_widget.cpp index 3e6b8b334..e8b89f674 100644 --- a/Telegram/SourceFiles/settings/settings_privacy_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_privacy_widget.cpp @@ -20,7 +20,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #include "settings/settings_privacy_widget.h" -#include "ui/effects/widget_slide_wrap.h" +#include "ui/wrap/slide_wrap.h" #include "ui/widgets/buttons.h" #include "styles/style_settings.h" #include "lang/lang_keys.h" @@ -36,7 +36,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org namespace Settings { -LocalPasscodeState::LocalPasscodeState(QWidget *parent) : TWidget(parent) +LocalPasscodeState::LocalPasscodeState(QWidget *parent) : RpWidget(parent) , _edit(this, GetEditPasscodeText(), st::boxLinkButton) , _turnOff(this, lang(lng_passcode_turn_off), st::boxLinkButton) { updateControls(); @@ -69,7 +69,7 @@ QString LocalPasscodeState::GetEditPasscodeText() { return lang(Global::LocalPasscode() ? lng_passcode_change : lng_passcode_turn_on); } -CloudPasswordState::CloudPasswordState(QWidget *parent) : TWidget(parent) +CloudPasswordState::CloudPasswordState(QWidget *parent) : RpWidget(parent) , _edit(this, lang(lng_cloud_password_set), st::boxLinkButton) , _turnOff(this, lang(lng_passcode_turn_off), st::boxLinkButton) { _turnOff->hide(); @@ -182,20 +182,20 @@ void PrivacyWidget::createControls() { style::margins marginSkip(0, 0, 0, st::settingsSkip); style::margins slidedPadding(0, marginSmall.bottom() / 2, 0, marginSmall.bottom() - (marginSmall.bottom() / 2)); - addChildRow(_blockedUsers, marginSmall, lang(lng_settings_blocked_users), SLOT(onBlockedUsers())); - addChildRow(_lastSeenPrivacy, marginSmall, lang(lng_settings_last_seen_privacy), SLOT(onLastSeenPrivacy())); - addChildRow(_callsPrivacy, marginSmall, lang(lng_settings_calls_privacy), SLOT(onCallsPrivacy())); - addChildRow(_groupsInvitePrivacy, marginSmall, lang(lng_settings_groups_invite_privacy), SLOT(onGroupsInvitePrivacy())); - addChildRow(_localPasscodeState, marginSmall); + createChildRow(_blockedUsers, marginSmall, lang(lng_settings_blocked_users), SLOT(onBlockedUsers())); + createChildRow(_lastSeenPrivacy, marginSmall, lang(lng_settings_last_seen_privacy), SLOT(onLastSeenPrivacy())); + createChildRow(_callsPrivacy, marginSmall, lang(lng_settings_calls_privacy), SLOT(onCallsPrivacy())); + createChildRow(_groupsInvitePrivacy, marginSmall, lang(lng_settings_groups_invite_privacy), SLOT(onGroupsInvitePrivacy())); + createChildRow(_localPasscodeState, marginSmall); auto label = lang(psIdleSupported() ? lng_passcode_autolock_away : lng_passcode_autolock_inactive); auto value = GetAutoLockText(); - addChildRow(_autoLock, marginSmall, slidedPadding, label, value, LabeledLink::Type::Primary, SLOT(onAutoLock())); + createChildRow(_autoLock, marginSmall, slidedPadding, label, value, LabeledLink::Type::Primary, SLOT(onAutoLock())); if (!Global::LocalPasscode()) { _autoLock->hideFast(); } - addChildRow(_cloudPasswordState, marginSmall); - addChildRow(_showAllSessions, marginSmall, lang(lng_settings_show_sessions), SLOT(onShowSessions())); - addChildRow(_selfDestruction, marginSmall, lang(lng_settings_self_destruct), SLOT(onSelfDestruction())); + createChildRow(_cloudPasswordState, marginSmall); + createChildRow(_showAllSessions, marginSmall, lang(lng_settings_show_sessions), SLOT(onShowSessions())); + createChildRow(_selfDestruction, marginSmall, lang(lng_settings_self_destruct), SLOT(onSelfDestruction())); } void PrivacyWidget::autoLockUpdated() { diff --git a/Telegram/SourceFiles/settings/settings_privacy_widget.h b/Telegram/SourceFiles/settings/settings_privacy_widget.h index 89a1c7941..0f87e1636 100644 --- a/Telegram/SourceFiles/settings/settings_privacy_widget.h +++ b/Telegram/SourceFiles/settings/settings_privacy_widget.h @@ -22,10 +22,11 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "settings/settings_block_widget.h" #include "settings/settings_chat_settings_widget.h" +#include "ui/rp_widget.h" namespace Settings { -class LocalPasscodeState : public TWidget, private base::Subscriber { +class LocalPasscodeState : public Ui::RpWidget, private base::Subscriber { Q_OBJECT public: @@ -48,7 +49,7 @@ private: }; -class CloudPasswordState : public TWidget, private base::Subscriber, public RPCSender { +class CloudPasswordState : public Ui::RpWidget, private base::Subscriber, public RPCSender { Q_OBJECT public: @@ -101,15 +102,15 @@ private: void createControls(); void autoLockUpdated(); - object_ptr _blockedUsers = { nullptr }; - object_ptr _lastSeenPrivacy = { nullptr }; - object_ptr _callsPrivacy = { nullptr }; - object_ptr _groupsInvitePrivacy = { nullptr }; - object_ptr _localPasscodeState = { nullptr }; - object_ptr> _autoLock = { nullptr }; - object_ptr _cloudPasswordState = { nullptr }; - object_ptr _showAllSessions = { nullptr }; - object_ptr _selfDestruction = { nullptr }; + Ui::LinkButton *_blockedUsers = nullptr; + Ui::LinkButton *_lastSeenPrivacy = nullptr; + Ui::LinkButton *_callsPrivacy = nullptr; + Ui::LinkButton *_groupsInvitePrivacy = nullptr; + LocalPasscodeState *_localPasscodeState = nullptr; + Ui::SlideWrap *_autoLock = nullptr; + CloudPasswordState *_cloudPasswordState = nullptr; + Ui::LinkButton *_showAllSessions = nullptr; + Ui::LinkButton *_selfDestruction = nullptr; }; diff --git a/Telegram/SourceFiles/settings/settings_scale_widget.cpp b/Telegram/SourceFiles/settings/settings_scale_widget.cpp index 698b76e7a..e555b4b47 100644 --- a/Telegram/SourceFiles/settings/settings_scale_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_scale_widget.cpp @@ -52,15 +52,17 @@ ScaleWidget::ScaleWidget(QWidget *parent, UserData *self) : BlockWidget(parent, void ScaleWidget::createControls() { style::margins margin(0, 0, 0, st::settingsSmallSkip); - addChildRow(_auto, margin, lng_settings_scale_auto(lt_cur, scaleLabel(cScreenScale())), [this](bool) { onAutoChanged(); }, (cConfigScale() == dbisAuto)); - addChildRow(_scale, style::margins(0, 0, 0, 0)); + createChildRow(_auto, margin, lng_settings_scale_auto(lt_cur, scaleLabel(cScreenScale())), [this](bool) { onAutoChanged(); }, (cConfigScale() == dbisAuto)); + createChildRow(_scale, style::margins(0, 0, 0, 0)); _scale->addSection(scaleLabel(dbisOne)); _scale->addSection(scaleLabel(dbisOneAndQuarter)); _scale->addSection(scaleLabel(dbisOneAndHalf)); _scale->addSection(scaleLabel(dbisTwo)); _scale->setActiveSectionFast(cEvalScale(cConfigScale()) - 1); - _scale->setSectionActivatedCallback([this] { scaleChanged(); }); + _scale->sectionActivated() + | rpl::on_next([this](int) { scaleChanged(); }) + | rpl::start(lifetime()); } void ScaleWidget::onAutoChanged() { diff --git a/Telegram/SourceFiles/settings/settings_scale_widget.h b/Telegram/SourceFiles/settings/settings_scale_widget.h index 7281ebbd3..9ff8282b4 100644 --- a/Telegram/SourceFiles/settings/settings_scale_widget.h +++ b/Telegram/SourceFiles/settings/settings_scale_widget.h @@ -43,8 +43,8 @@ private: void createControls(); void setScale(DBIScale newScale); - object_ptr _auto = { nullptr }; - object_ptr _scale = { nullptr }; + Ui::Checkbox *_auto = nullptr; + Ui::SettingsSlider *_scale = nullptr; DBIScale _newScale = dbisAuto; bool _inSetScale = false; diff --git a/Telegram/SourceFiles/settings/settings_widget.cpp b/Telegram/SourceFiles/settings/settings_widget.cpp index c39e22c6d..94aa2bc2b 100644 --- a/Telegram/SourceFiles/settings/settings_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_widget.cpp @@ -245,7 +245,7 @@ void Widget::parentResized() { } void Widget::resizeUsingInnerHeight(int newWidth, int innerHeight) { - if (!App::wnd()) return; + if (!parentWidget()) return; auto parentSize = parentWidget()->size(); auto windowWidth = parentSize.width(); diff --git a/Telegram/SourceFiles/settings/settings_widget.h b/Telegram/SourceFiles/settings/settings_widget.h index b10b2caf5..e432ca67d 100644 --- a/Telegram/SourceFiles/settings/settings_widget.h +++ b/Telegram/SourceFiles/settings/settings_widget.h @@ -27,8 +27,6 @@ namespace Settings { class InnerWidget; class Widget : public Layer, private base::Subscriber { - Q_OBJECT - public: Widget(QWidget*); diff --git a/Telegram/SourceFiles/storage/storage_facade.h b/Telegram/SourceFiles/storage/storage_facade.h index 86264a206..d131dfa61 100644 --- a/Telegram/SourceFiles/storage/storage_facade.h +++ b/Telegram/SourceFiles/storage/storage_facade.h @@ -20,8 +20,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #pragma once +#include #include "base/enum_mask.h" -#include "rpl/producer.h" namespace Storage { diff --git a/Telegram/SourceFiles/storage/storage_shared_media.h b/Telegram/SourceFiles/storage/storage_shared_media.h index ea46ef296..ec14cd604 100644 --- a/Telegram/SourceFiles/storage/storage_shared_media.h +++ b/Telegram/SourceFiles/storage/storage_shared_media.h @@ -20,8 +20,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #pragma once +#include #include "storage/storage_facade.h" -#include "rpl/event_stream.h" namespace Storage { diff --git a/Telegram/SourceFiles/storage/storage_user_photos.h b/Telegram/SourceFiles/storage/storage_user_photos.h index ba6184c78..1ce6096b8 100644 --- a/Telegram/SourceFiles/storage/storage_user_photos.h +++ b/Telegram/SourceFiles/storage/storage_user_photos.h @@ -20,8 +20,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #pragma once +#include #include "storage/storage_facade.h" -#include "rpl/event_stream.h" namespace Storage { diff --git a/Telegram/SourceFiles/ui/abstract_button.cpp b/Telegram/SourceFiles/ui/abstract_button.cpp index 11be386b1..1bca92f14 100644 --- a/Telegram/SourceFiles/ui/abstract_button.cpp +++ b/Telegram/SourceFiles/ui/abstract_button.cpp @@ -71,6 +71,7 @@ void AbstractButton::mouseReleaseEvent(QMouseEvent *e) { onStateChanged(was, StateChangeSource::ByPress); if (was & StateFlag::Over) { _modifiers = e->modifiers(); + _clicks.fire({}); if (_clickedCallback) { _clickedCallback(); } else { diff --git a/Telegram/SourceFiles/ui/abstract_button.h b/Telegram/SourceFiles/ui/abstract_button.h index 7affcbaa3..283d5c29e 100644 --- a/Telegram/SourceFiles/ui/abstract_button.h +++ b/Telegram/SourceFiles/ui/abstract_button.h @@ -20,16 +20,17 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #pragma once -#include "ui/twidget.h" +#include +#include "ui/rp_widget.h" #include "base/flags.h" namespace Ui { -class AbstractButton : public TWidget { +class AbstractButton : public RpWidget { Q_OBJECT public: - AbstractButton(QWidget *parent) : TWidget(parent) { + AbstractButton(QWidget *parent) : RpWidget(parent) { setMouseTracking(true); } @@ -64,6 +65,10 @@ public: } } + rpl::producer<> clicks() const { + return _clicks.events(); + } + protected: void enterEventHook(QEvent *e) override; void leaveEventHook(QEvent *e) override; @@ -109,6 +114,8 @@ private: base::lambda _clickedCallback; + rpl::event_stream<> _clicks; + }; } // namespace Ui diff --git a/Telegram/SourceFiles/ui/effects/widget_slide_wrap.cpp b/Telegram/SourceFiles/ui/effects/widget_slide_wrap.cpp index 239f83e6e..c791d37c5 100644 --- a/Telegram/SourceFiles/ui/effects/widget_slide_wrap.cpp +++ b/Telegram/SourceFiles/ui/effects/widget_slide_wrap.cpp @@ -22,115 +22,159 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org namespace Ui { -WidgetSlideWrap::WidgetSlideWrap(QWidget *parent -, object_ptr entity -, style::margins entityPadding -, base::lambda updateCallback -, int duration) : TWidget(parent) -, _entity(std::move(entity)) -, _padding(entityPadding) -, _duration(duration) -, _updateCallback(std::move(updateCallback)) { - _entity->setParent(this); - auto margins = getMargins(); - _entity->moveToLeft(margins.left() + _padding.left(), margins.top() + _padding.top()); - _realSize = _entity->rectNoMargins().marginsAdded(_padding).size(); - _entity->installEventFilter(this); - resizeToWidth(_realSize.width()); -} - -void WidgetSlideWrap::hideAnimated() { - if (isHidden()) { - _forceHeight = 0; - resizeToWidth(_realSize.width()); - if (_updateCallback) _updateCallback(); - return; - } - if (_a_height.animating()) { - if (_hiding) return; - } - _hiding = true; - _a_height.start([this] { animationCallback(); }, _realSize.height(), 0., _duration); -} - -void WidgetSlideWrap::showAnimated() { - if (isHidden()) { - show(); - } - if (_forceHeight < 0) { - return; - } - - if (_a_height.animating()) { - if (!_hiding) return; - } - _hiding = false; - _forceHeight = qRound(_a_height.current(0.)); - _a_height.start([this] { animationCallback(); }, 0., _realSize.height(), _duration); -} - -void WidgetSlideWrap::toggleFast(bool visible) { - _hiding = !visible; - if (!_hiding) show(); - _a_height.finish(); - _forceHeight = _hiding ? 0 : -1; - resizeToWidth(_realSize.width()); - if (_hiding) hide(); - if (_updateCallback) { - _updateCallback(); +PaddingWrap::PaddingWrap( + QWidget *parent, + object_ptr child, + const style::margins &padding) +: Parent(parent, std::move(child)) +, _padding(padding) { + if (auto weak = wrapped()) { + auto margins = weak->getMargins(); + weak->sizeValue() + | rpl::on_next([this](QSize&&) { updateSize(); }) + | rpl::start(lifetime()); + weak->moveToLeft(_padding.left() + margins.left(), _padding.top() + margins.top()); } } -QMargins WidgetSlideWrap::getMargins() const { - auto entityMargins = _entity->getMargins(); - if (_forceHeight < 0) { - return entityMargins; - } - return QMargins(entityMargins.left(), 0, entityMargins.right(), 0); -} - -int WidgetSlideWrap::naturalWidth() const { - auto inner = _entity->naturalWidth(); - return (inner < 0) ? inner : (_padding.left() + inner + _padding.right()); -} - -bool WidgetSlideWrap::eventFilter(QObject *object, QEvent *event) { - if (object == _entity && event->type() == QEvent::Resize) { - _realSize = _entity->rectNoMargins().marginsAdded(_padding).size(); - if (!_inResizeToWidth) { - resizeToWidth(_realSize.width()); - if (_updateCallback) { - _updateCallback(); - } +void PaddingWrap::updateSize() { + auto inner = [this] { + if (auto weak = wrapped()) { + return weak->rect(); } - } - return TWidget::eventFilter(object, event); + return QRect(0, 0, _innerWidth, 0); + }(); + resize(inner.marginsAdded(_padding).size()); } -int WidgetSlideWrap::resizeGetHeight(int newWidth) { - _inResizeToWidth = true; - auto resized = (_forceHeight >= 0); - _entity->resizeToWidth(newWidth - _padding.left() - _padding.right()); - auto margins = getMargins(); - _entity->moveToLeft(margins.left() + _padding.left(), margins.top() + _padding.top()); - _inResizeToWidth = false; - if (resized) { - return _forceHeight; - } - _realSize = _entity->rectNoMargins().marginsAdded(_padding).size(); - return _realSize.height(); +int PaddingWrap::naturalWidth() const { + auto inner = [this] { + if (auto weak = wrapped()) { + return weak->naturalWidth(); + } + return RpWidget::naturalWidth(); + }(); + return (inner < 0) + ? inner + : (_padding.left() + inner + _padding.right()); } -void WidgetSlideWrap::animationCallback() { - _forceHeight = qRound(_a_height.current(_hiding ? 0 : -1)); - resizeToWidth(_realSize.width()); - if (!_a_height.animating()) { - _forceHeight = _hiding ? 0 : -1; - if (_hiding) hide(); +int PaddingWrap::resizeGetHeight(int newWidth) { + _innerWidth = newWidth; + if (auto weak = wrapped()) { + weak->resizeToWidth(newWidth + - _padding.left() + - _padding.right()); + } else { + updateSize(); } - if (_updateCallback) { - _updateCallback(); + return height(); +} + +SlideWrap::SlideWrap( + QWidget *parent, + object_ptr child) +: SlideWrap( + parent, + std::move(child), + style::margins(), + st::slideWrapDuration) { +} + +SlideWrap::SlideWrap( + QWidget *parent, + object_ptr child, + const style::margins &padding) +: SlideWrap( + parent, + std::move(child), + padding, + st::slideWrapDuration) { +} + +SlideWrap::SlideWrap( + QWidget *parent, + object_ptr child, + int duration) +: SlideWrap(parent, std::move(child), style::margins(), duration) { +} + +SlideWrap::SlideWrap( + QWidget *parent, + object_ptr child, + const style::margins &padding, + int duration) +: Parent(parent, object_ptr>(parent, std::move(child), padding)) +, _duration(duration * 10) { + if (auto weak = wrapped()) { + weak->heightValue() + | rpl::on_next([this](int newHeight) { + if (_slideAnimation.animating()) { + animationStep(); + } else if (_visible) { + resize(width(), newHeight); + } + }) | rpl::start(lifetime()); } } +void SlideWrap::animationStep() { + if (wrapped()) { + auto margins = getMargins(); + wrapped()->moveToLeft(margins.left(), margins.top()); + } + auto current = _slideAnimation.current(_visible ? 1. : 0.); + auto newHeight = wrapped() + ? (_slideAnimation.animating() + ? anim::interpolate(0, wrapped()->heightNoMargins(), current) + : (_visible ? wrapped()->height() : 0)) + : 0; + if (newHeight != height()) { + resize(width(), newHeight); + } + auto shouldBeHidden = !_visible && !_slideAnimation.animating(); + if (shouldBeHidden != isHidden()) { + setVisible(!shouldBeHidden); + } +} + +void SlideWrap::toggleAnimated(bool visible) { + if (_visible == visible) { + animationStep(); + return; + } + _visible = visible; + _slideAnimation.start( + [this] { animationStep(); }, + _visible ? 0. : 1., + _visible ? 1. : 0., + _duration, + anim::linear); + animationStep(); +} + +void SlideWrap::toggleFast(bool visible) { + _visible = visible; + finishAnimations(); +} + +void SlideWrap::finishAnimations() { + _slideAnimation.finish(); + animationStep(); +} + +QMargins SlideWrap::getMargins() const { + auto result = wrapped()->getMargins(); + return (animating() || !_visible) + ? QMargins(result.left(), 0, result.right(), 0) + : result; +} + +int SlideWrap::resizeGetHeight(int newWidth) { + if (wrapped()) { + wrapped()->resizeToWidth(newWidth); + } + return height(); +} + } // namespace Ui diff --git a/Telegram/SourceFiles/ui/effects/widget_slide_wrap.h b/Telegram/SourceFiles/ui/effects/widget_slide_wrap.h index a22f57abf..36e59aaea 100644 --- a/Telegram/SourceFiles/ui/effects/widget_slide_wrap.h +++ b/Telegram/SourceFiles/ui/effects/widget_slide_wrap.h @@ -21,100 +21,263 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #pragma once #include "styles/style_widgets.h" +#include "ui/rp_widget.h" namespace Ui { +template +class Wrap; + +namespace details { + +struct UnwrapHelper { + struct Large { + char data[2]; + }; + static char Check(...); + template + static Large Check(Wrap*); + template + static Large Check(const Wrap*); + + template + static constexpr bool Is() { + return sizeof(Check(std::declval())) + == sizeof(Large); + } + template + static auto Unwrap(Entity *entity, std::true_type) { + return entity + ? entity->entity() + : nullptr; + } + template + static Entity *Unwrap(Entity *entity, std::false_type) { + return entity; + } + template + static auto Unwrap(Entity *entity) { + return Unwrap( + entity, + std::integral_constant()>()); + } +}; + +} // namespace details + template -class WidgetSlideWrap; +class Wrap : public RpWidget { +public: + Wrap(QWidget *parent, object_ptr child); + + Widget *wrapped() { + return _wrapped; + } + const Widget *wrapped() const { + return _wrapped; + } + auto entity() { + return details::UnwrapHelper::Unwrap(wrapped()); + } + auto entity() const { + return details::UnwrapHelper::Unwrap(wrapped()); + } + + QMargins getMargins() const override { + if (auto weak = wrapped()) { + return weak->getMargins(); + } + return RpWidget::getMargins(); + } + int naturalWidth() const override { + if (auto weak = wrapped()) { + return weak->naturalWidth(); + } + return RpWidget::naturalWidth(); + } + +private: + object_ptr _wrapped; + +}; + +template +Wrap::Wrap(QWidget *parent, object_ptr child) +: RpWidget(parent) +, _wrapped(std::move(child)) { + if (_wrapped) { + resize(_wrapped->size()); + AttachParentChild(this, _wrapped); + _wrapped->move(0, 0); + _wrapped->alive() + | rpl::on_done([this] { + _wrapped->setParent(nullptr); + _wrapped = nullptr; + delete this; + }) + | rpl::start(lifetime()); + } +} + +template +class Wrap : public ParentType { +public: + using ParentType::ParentType; + + Widget *wrapped() { + return static_cast(ParentType::wrapped()); + } + const Widget *wrapped() const { + return static_cast(ParentType::wrapped()); + } + auto entity() { + return details::UnwrapHelper::Unwrap(wrapped()); + } + auto entity() const { + return details::UnwrapHelper::Unwrap(wrapped()); + } + +}; + +template +class PaddingWrap; template <> -class WidgetSlideWrap : public TWidget { -public: - WidgetSlideWrap(QWidget *parent - , object_ptr entity - , style::margins entityPadding - , base::lambda updateCallback - , int duration = st::widgetSlideDuration); +class PaddingWrap : public Wrap { + using Parent = Wrap; - void showAnimated(); - void hideAnimated(); - void toggleAnimated(bool visible) { - if (visible) { - showAnimated(); - } else { - hideAnimated(); - } +public: + PaddingWrap( + QWidget *parent, + object_ptr child, + const style::margins &padding); + + PaddingWrap( + QWidget *parent, + const style::margins &padding) + : PaddingWrap(parent, nullptr, padding) { } + + int naturalWidth() const override; + +protected: + int resizeGetHeight(int newWidth) override; + +private: + void updateSize(); + + int _innerWidth = 0; + style::margins _padding; + +}; + +template +class PaddingWrap : public Wrap> { + using Parent = Wrap>; + +public: + PaddingWrap( + QWidget *parent, + object_ptr child, + const style::margins &padding) + : Parent(parent, std::move(child), padding) { + } + + PaddingWrap(QWidget *parent, const style::margins &padding) + : Parent(parent, padding) { + } + +}; + +template +class SlideWrap; + +template <> +class SlideWrap : public Wrap> { + using Parent = Wrap>; + +public: + SlideWrap(QWidget *parent, object_ptr child); + SlideWrap( + QWidget *parent, + object_ptr child, + const style::margins &padding); + SlideWrap( + QWidget *parent, + object_ptr child, + int duration); + SlideWrap( + QWidget *parent, + object_ptr child, + const style::margins &padding, + int duration); + + void toggleAnimated(bool visible); + void toggleFast(bool visible); + + void showAnimated() { + toggleAnimated(true); + } + void hideAnimated() { + toggleAnimated(false); + } + void showFast() { toggleFast(true); } void hideFast() { toggleFast(false); } - void toggleFast(bool visible); - bool isHiddenOrHiding() const { - return isHidden() || (_a_height.animating() && _hiding); - } - - void finishAnimation() { - _a_height.finish(); - myEnsureResized(_entity); - animationCallback(); - } bool animating() const { - return _a_height.animating(); - } - - TWidget *entity() { - return _entity; - } - - const TWidget *entity() const { - return _entity; + return _slideAnimation.animating(); } + void finishAnimations(); QMargins getMargins() const override; - int naturalWidth() const override; + + bool isHiddenOrHiding() const { + return !_visible; + } protected: - bool eventFilter(QObject *object, QEvent *event) override; int resizeGetHeight(int newWidth) override; private: - void animationCallback(); + void animationStep(); - object_ptr _entity; - bool _inResizeToWidth = false; - style::margins _padding; - int _duration; - base::lambda _updateCallback; - - style::size _realSize; - int _forceHeight = -1; - Animation _a_height; - bool _hiding = false; + bool _visible = true; + Animation _slideAnimation; + int _duration = 0; }; template -class WidgetSlideWrap : public WidgetSlideWrap { +class SlideWrap : public Wrap, SlideWrap> { + using Parent = Wrap, SlideWrap>; + public: - WidgetSlideWrap(QWidget *parent - , object_ptr entity - , style::margins entityPadding - , base::lambda updateCallback - , int duration = st::widgetSlideDuration) : WidgetSlideWrap(parent - , std::move(entity) - , entityPadding - , std::move(updateCallback) - , duration) { + SlideWrap(QWidget *parent, object_ptr child) + : Parent(parent, std::move(child)) { } - Widget *entity() { - return static_cast(WidgetSlideWrap::entity()); + SlideWrap( + QWidget *parent, + object_ptr child, + const style::margins &padding) + : Parent(parent, std::move(child), padding) { } - const Widget *entity() const { - return static_cast(WidgetSlideWrap::entity()); + SlideWrap( + QWidget *parent, + object_ptr child, + int duration) + : Parent(parent, std::move(child), duration) { + } + SlideWrap( + QWidget *parent, + object_ptr child, + const style::margins &padding, + int duration) + : Parent(parent, std::move(child), padding, duration) { } }; diff --git a/Telegram/SourceFiles/ui/rp_widget.h b/Telegram/SourceFiles/ui/rp_widget.h new file mode 100644 index 000000000..eb9b3c14b --- /dev/null +++ b/Telegram/SourceFiles/ui/rp_widget.h @@ -0,0 +1,130 @@ +/* +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-2017 John Preston, https://desktop.telegram.org +*/ +#pragma once + +#include +#include +#include + +namespace Ui { + +class RpWidget : public TWidget { +public: + RpWidget::RpWidget(QWidget *parent = nullptr) : TWidget(parent) { + setGeometry(0, 0, 0, 0); + } + + rpl::producer geometryValue() const { + auto &stream = eventFilter().geometry; + return stream.events_starting_with_copy(geometry()); + } + rpl::producer sizeValue() const { + return geometryValue() + | rpl::map([](QRect &&value) { return value.size(); }) + | rpl::distinct_until_changed(); + } + rpl::producer heightValue() const { + return geometryValue() + | rpl::map([](QRect &&value) { return value.height(); }) + | rpl::distinct_until_changed(); + } + rpl::producer widthValue() const { + return geometryValue() + | rpl::map([](QRect &&value) { return value.width(); }) + | rpl::distinct_until_changed(); + } + rpl::producer positionValue() const { + return geometryValue() + | rpl::map([](QRect &&value) { return value.topLeft(); }) + | rpl::distinct_until_changed(); + } + rpl::producer leftValue() const { + return geometryValue() + | rpl::map([](QRect &&value) { return value.left(); }) + | rpl::distinct_until_changed(); + } + rpl::producer topValue() const { + return geometryValue() + | rpl::map([](QRect &&value) { return value.top(); }) + | rpl::distinct_until_changed(); + } + virtual rpl::producer desiredHeightValue() const { + return heightValue(); + } + + rpl::producer paintRequest() const { + return eventFilter().paint.events(); + } + + rpl::producer<> alive() const { + return eventFilter().alive.events(); + } + + rpl::lifetime &lifetime() { + return _lifetime; + } + +private: + class EventFilter : public QObject { + public: + EventFilter(RpWidget *parent) : QObject(parent) { + parent->installEventFilter(this); + } + rpl::event_stream geometry; + rpl::event_stream paint; + rpl::event_stream<> alive; + + protected: + bool eventFilter(QObject *object, QEvent *event) { + auto widget = static_cast(parent()); + + switch (event->type()) { + case QEvent::Move: + case QEvent::Resize: + geometry.fire_copy(widget->geometry()); + break; + + case QEvent::Paint: + paint.fire_copy( + static_cast(event)->rect()); + break; + } + + return QObject::eventFilter(object, event); + } + + }; + + EventFilter &eventFilter() const { + if (!_eventFilter) { + auto that = const_cast(this); + that->_eventFilter = std::make_unique(that); + } + return *_eventFilter; + } + + std::unique_ptr _eventFilter; + + rpl::lifetime _lifetime; + +}; + +} // namespace Ui diff --git a/Telegram/SourceFiles/ui/twidget.h b/Telegram/SourceFiles/ui/twidget.h index 902f240f4..2692ed1f1 100644 --- a/Telegram/SourceFiles/ui/twidget.h +++ b/Telegram/SourceFiles/ui/twidget.h @@ -57,18 +57,6 @@ inline ChildWidget *AttachParentChild( return nullptr; } -template -inline ChildWidget *AttachParentChildToBottom( - not_null parent, - const object_ptr &child) { - if (auto raw = AttachParentChild(parent, child)) { - raw->resizeToWidth(parent->width()); - raw->move(0, parent->height()); - return raw; - } - return nullptr; -} - } // namespace Ui enum class RectPart { @@ -288,7 +276,7 @@ public: QRect mapFromGlobal(const QRect &rect) const { return QRect(mapFromGlobal(rect.topLeft()), rect.size()); } - QRect mapToGlobal(const QRect &rect) { + QRect mapToGlobal(const QRect &rect) const { return QRect(mapToGlobal(rect.topLeft()), rect.size()); } @@ -410,7 +398,11 @@ public: } // Updates the area that is visible inside the scroll container. - virtual void setVisibleTopBottom(int visibleTop, int visibleBottom) { + void setVisibleTopBottom(int visibleTop, int visibleBottom) { + auto max = height(); + visibleTopBottomUpdated( + snap(visibleTop, 0, max), + snap(visibleBottom, 0, max)); } signals: @@ -418,11 +410,28 @@ signals: void heightUpdated(); protected: + void setChildVisibleTopBottom( + TWidget *child, + int visibleTop, + int visibleBottom) { + if (child) { + auto top = child->y(); + child->setVisibleTopBottom( + visibleTop - top, + visibleBottom - top); + } + } + // Resizes content and counts natural widget height for the desired width. virtual int resizeGetHeight(int newWidth) { return height(); } + virtual void visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) { + } + }; template diff --git a/Telegram/SourceFiles/ui/widgets/discrete_sliders.cpp b/Telegram/SourceFiles/ui/widgets/discrete_sliders.cpp index 8f1fb8941..caedaff7b 100644 --- a/Telegram/SourceFiles/ui/widgets/discrete_sliders.cpp +++ b/Telegram/SourceFiles/ui/widgets/discrete_sliders.cpp @@ -25,14 +25,10 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org namespace Ui { -DiscreteSlider::DiscreteSlider(QWidget *parent) : TWidget(parent) { +DiscreteSlider::DiscreteSlider(QWidget *parent) : RpWidget(parent) { setCursor(style::cur_pointer); } -void DiscreteSlider::setSectionActivatedCallback(SectionActivatedCallback &&callback) { - _callback = std::move(callback); -} - void DiscreteSlider::setActiveSection(int index) { if (_activeIndex != index) { _activeIndex = index; @@ -48,9 +44,7 @@ void DiscreteSlider::activateCallback() { } auto ms = getms(); if (ms >= _callbackAfterMs) { - if (_callback) { - _callback(); - } + _sectionActivated.fire_copy(_activeIndex); } else { _timerId = startTimer(_callbackAfterMs - ms, Qt::PreciseTimer); } @@ -62,6 +56,10 @@ void DiscreteSlider::timerEvent(QTimerEvent *e) { void DiscreteSlider::setActiveSectionFast(int index) { setActiveSection(index); + finishAnimations(); +} + +void DiscreteSlider::finishAnimations() { _a_left.finish(); update(); } diff --git a/Telegram/SourceFiles/ui/widgets/discrete_sliders.h b/Telegram/SourceFiles/ui/widgets/discrete_sliders.h index 5a324b254..de2fc7105 100644 --- a/Telegram/SourceFiles/ui/widgets/discrete_sliders.h +++ b/Telegram/SourceFiles/ui/widgets/discrete_sliders.h @@ -20,13 +20,15 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #pragma once +#include +#include "ui/rp_widget.h" #include "styles/style_widgets.h" namespace Ui { class RippleAnimation; -class DiscreteSlider : public TWidget { +class DiscreteSlider : public RpWidget { public: DiscreteSlider(QWidget *parent); @@ -37,9 +39,11 @@ public: } void setActiveSection(int index); void setActiveSectionFast(int index); + void finishAnimations(); - using SectionActivatedCallback = base::lambda; - void setSectionActivatedCallback(SectionActivatedCallback &&callback); + rpl::producer sectionActivated() const { + return _sectionActivated.events(); + } protected: void timerEvent(QTimerEvent *e) override; @@ -88,7 +92,7 @@ private: int _activeIndex = 0; bool _selectOnPress = true; - SectionActivatedCallback _callback; + rpl::event_stream _sectionActivated; int _pressed = -1; int _selected = 0; diff --git a/Telegram/SourceFiles/ui/widgets/inner_dropdown.cpp b/Telegram/SourceFiles/ui/widgets/inner_dropdown.cpp index ca1393f7a..032a8c51c 100644 --- a/Telegram/SourceFiles/ui/widgets/inner_dropdown.cpp +++ b/Telegram/SourceFiles/ui/widgets/inner_dropdown.cpp @@ -372,8 +372,10 @@ InnerDropdown::Container::Container(QWidget *parent, object_ptr child, _child->moveToLeft(_st.scrollPadding.left(), _st.scrollPadding.top()); } -void InnerDropdown::Container::setVisibleTopBottom(int visibleTop, int visibleBottom) { - _child->setVisibleTopBottom(visibleTop - _st.scrollPadding.top(), visibleBottom - _st.scrollPadding.top()); +void InnerDropdown::Container::visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) { + setChildVisibleTopBottom(_child, visibleTop, visibleBottom); } void InnerDropdown::Container::resizeToContent() { diff --git a/Telegram/SourceFiles/ui/widgets/inner_dropdown.h b/Telegram/SourceFiles/ui/widgets/inner_dropdown.h index 17d9ae8e8..82984161e 100644 --- a/Telegram/SourceFiles/ui/widgets/inner_dropdown.h +++ b/Telegram/SourceFiles/ui/widgets/inner_dropdown.h @@ -141,12 +141,14 @@ private: class InnerDropdown::Container : public TWidget { public: Container(QWidget *parent, object_ptr child, const style::InnerDropdown &st); - void setVisibleTopBottom(int visibleTop, int visibleBottom) override; void resizeToContent(); protected: int resizeGetHeight(int newWidth) override; + void visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) override; private: object_ptr _child; diff --git a/Telegram/SourceFiles/ui/widgets/labels.cpp b/Telegram/SourceFiles/ui/widgets/labels.cpp index ec617bb41..728e38c66 100644 --- a/Telegram/SourceFiles/ui/widgets/labels.cpp +++ b/Telegram/SourceFiles/ui/widgets/labels.cpp @@ -137,14 +137,20 @@ void LabelSimple::paintEvent(QPaintEvent *e) { p.drawTextLeft(0, 0, width(), _text, _textWidth); } -FlatLabel::FlatLabel(QWidget *parent, const style::FlatLabel &st) : TWidget(parent) +FlatLabel::FlatLabel(QWidget *parent, const style::FlatLabel &st) +: RpWidget(parent) , _text(st.width ? st.width : QFIXED_MAX) , _st(st) , _contextCopyText(lang(lng_context_copy_text)) { init(); } -FlatLabel::FlatLabel(QWidget *parent, const QString &text, InitType initType, const style::FlatLabel &st) : TWidget(parent) +FlatLabel::FlatLabel( + QWidget *parent, + const QString &text, + InitType initType, + const style::FlatLabel &st) +: RpWidget(parent) , _text(st.width ? st.width : QFIXED_MAX) , _st(st) , _contextCopyText(lang(lng_context_copy_text)) { @@ -156,6 +162,36 @@ FlatLabel::FlatLabel(QWidget *parent, const QString &text, InitType initType, co init(); } +FlatLabel::FlatLabel( + QWidget *parent, + rpl::producer &&text, + const style::FlatLabel &st) +: RpWidget(parent) +, _text(st.width ? st.width : QFIXED_MAX) +, _st(st) +, _contextCopyText(lang(lng_context_copy_text)) { + std::move(text) + | rpl::on_next([this](QString &&value) { + setText(std::move(value)); + }) + | rpl::start(lifetime()); +} + +FlatLabel::FlatLabel( + QWidget *parent, + rpl::producer &&text, + const style::FlatLabel &st) +: RpWidget(parent) +, _text(st.width ? st.width : QFIXED_MAX) +, _st(st) +, _contextCopyText(lang(lng_context_copy_text)) { + std::move(text) + | rpl::on_next([this](TextWithEntities &&value) { + setMarkedText(std::move(value)); + }) + | rpl::start(lifetime()); +} + void FlatLabel::init() { _trippleClickTimer.setSingleShot(true); diff --git a/Telegram/SourceFiles/ui/widgets/labels.h b/Telegram/SourceFiles/ui/widgets/labels.h index 210ece9dc..ed271a211 100644 --- a/Telegram/SourceFiles/ui/widgets/labels.h +++ b/Telegram/SourceFiles/ui/widgets/labels.h @@ -20,6 +20,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #pragma once +#include +#include "ui/rp_widget.h" #include "styles/style_widgets.h" namespace Ui { @@ -78,7 +80,7 @@ private: }; -class FlatLabel : public TWidget, public ClickHandlerHost { +class FlatLabel : public RpWidget, public ClickHandlerHost { Q_OBJECT public: @@ -88,7 +90,20 @@ public: Simple, Rich, }; - FlatLabel(QWidget *parent, const QString &text, InitType initType, const style::FlatLabel &st = st::defaultFlatLabel); + FlatLabel( + QWidget *parent, + const QString &text, + InitType initType, + const style::FlatLabel &st = st::defaultFlatLabel); + + FlatLabel( + QWidget *parent, + rpl::producer &&text, + const style::FlatLabel &st = st::defaultFlatLabel); + FlatLabel( + QWidget *parent, + rpl::producer &&text, + const style::FlatLabel &st = st::defaultFlatLabel); void setOpacity(float64 o); diff --git a/Telegram/SourceFiles/ui/widgets/multi_select.cpp b/Telegram/SourceFiles/ui/widgets/multi_select.cpp index e73c441ba..3a2aa2f60 100644 --- a/Telegram/SourceFiles/ui/widgets/multi_select.cpp +++ b/Telegram/SourceFiles/ui/widgets/multi_select.cpp @@ -243,7 +243,11 @@ void MultiSelect::Item::setOver(bool over) { } } -MultiSelect::MultiSelect(QWidget *parent, const style::MultiSelect &st, base::lambda placeholderFactory) : TWidget(parent) +MultiSelect::MultiSelect( + QWidget *parent, + const style::MultiSelect &st, + base::lambda placeholderFactory) +: RpWidget(parent) , _st(st) , _scroll(this, _st.scroll) { _inner = _scroll->setOwnedWidget(object_ptr(this, st, std::move(placeholderFactory), [this](int activeTop, int activeBottom) { diff --git a/Telegram/SourceFiles/ui/widgets/multi_select.h b/Telegram/SourceFiles/ui/widgets/multi_select.h index 8f1c208f6..cb6cdd2aa 100644 --- a/Telegram/SourceFiles/ui/widgets/multi_select.h +++ b/Telegram/SourceFiles/ui/widgets/multi_select.h @@ -21,6 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #pragma once #include "styles/style_widgets.h" +#include "ui/rp_widget.h" namespace Ui { @@ -28,7 +29,7 @@ class InputField; class CrossButton; class ScrollArea; -class MultiSelect : public TWidget { +class MultiSelect : public RpWidget { public: MultiSelect(QWidget *parent, const style::MultiSelect &st, base::lambda placeholderFactory = base::lambda()); diff --git a/Telegram/SourceFiles/ui/widgets/scroll_area.cpp b/Telegram/SourceFiles/ui/widgets/scroll_area.cpp index a493b647e..945166bb5 100644 --- a/Telegram/SourceFiles/ui/widgets/scroll_area.cpp +++ b/Telegram/SourceFiles/ui/widgets/scroll_area.cpp @@ -383,6 +383,7 @@ void ScrollArea::onScrolled() { _verticalBar->hideTimeout(_st.hiding); } em = true; + _scrollTopUpdated.fire_copy(_verticalValue); } } if (em) { diff --git a/Telegram/SourceFiles/ui/widgets/scroll_area.h b/Telegram/SourceFiles/ui/widgets/scroll_area.h index 1c2debfde..dc70a283b 100644 --- a/Telegram/SourceFiles/ui/widgets/scroll_area.h +++ b/Telegram/SourceFiles/ui/widgets/scroll_area.h @@ -20,6 +20,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #pragma once +#include #include "styles/style_widgets.h" namespace Ui { @@ -204,6 +205,10 @@ public: bool viewportEvent(QEvent *e) override; void keyPressEvent(QKeyEvent *e) override; + rpl::producer scrollTopValue() const { + return _scrollTopUpdated.events_starting_with(scrollTop()); + } + protected: bool eventFilter(QObject *obj, QEvent *e) override; @@ -283,6 +288,8 @@ private: object_ptr _widget = { nullptr }; + rpl::event_stream _scrollTopUpdated; + }; class SplittedWidgetOther : public TWidget { diff --git a/Telegram/SourceFiles/ui/wrap/padding_wrap.cpp b/Telegram/SourceFiles/ui/wrap/padding_wrap.cpp new file mode 100644 index 000000000..4e8152925 --- /dev/null +++ b/Telegram/SourceFiles/ui/wrap/padding_wrap.cpp @@ -0,0 +1,68 @@ +/* +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-2017 John Preston, https://desktop.telegram.org +*/ +#include "ui/wrap/padding_wrap.h" + +namespace Ui { + +PaddingWrap::PaddingWrap( + QWidget *parent, + object_ptr child, + const style::margins &padding) +: Parent(parent, std::move(child)) +, _padding(padding) { + if (auto weak = wrapped()) { + wrappedSizeUpdated(weak->size()); + + auto margins = weak->getMargins(); + weak->moveToLeft(_padding.left() + margins.left(), _padding.top() + margins.top()); + } +} + +void PaddingWrap::wrappedSizeUpdated(QSize size) { + resize(QRect(QPoint(), size).marginsAdded(_padding).size()); +} + +int PaddingWrap::naturalWidth() const { + auto inner = [this] { + if (auto weak = wrapped()) { + return weak->naturalWidth(); + } + return RpWidget::naturalWidth(); + }(); + return (inner < 0) + ? inner + : (_padding.left() + inner + _padding.right()); +} + +int PaddingWrap::resizeGetHeight(int newWidth) { + if (auto weak = wrapped()) { + weak->resizeToWidth(newWidth + - _padding.left() + - _padding.right()); + } else { + resize(QSize( + _padding.left() + newWidth + _padding.right(), + _padding.top() + _padding.bottom())); + } + return heightNoMargins(); +} + +} // namespace Ui diff --git a/Telegram/SourceFiles/ui/wrap/padding_wrap.h b/Telegram/SourceFiles/ui/wrap/padding_wrap.h new file mode 100644 index 000000000..882141a67 --- /dev/null +++ b/Telegram/SourceFiles/ui/wrap/padding_wrap.h @@ -0,0 +1,75 @@ +/* +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-2017 John Preston, https://desktop.telegram.org +*/ +#pragma once + +#include "ui/wrap/wrap.h" + +namespace Ui { + +template +class PaddingWrap; + +template <> +class PaddingWrap : public Wrap { + using Parent = Wrap; + +public: + PaddingWrap( + QWidget *parent, + object_ptr child, + const style::margins &padding); + + PaddingWrap( + QWidget *parent, + const style::margins &padding) + : PaddingWrap(parent, nullptr, padding) { + } + + int naturalWidth() const override; + +protected: + int resizeGetHeight(int newWidth) override; + void wrappedSizeUpdated(QSize size) override; + +private: + style::margins _padding; + +}; + +template +class PaddingWrap : public Wrap> { + using Parent = Wrap>; + +public: + PaddingWrap( + QWidget *parent, + object_ptr child, + const style::margins &padding) + : Parent(parent, std::move(child), padding) { + } + + PaddingWrap(QWidget *parent, const style::margins &padding) + : Parent(parent, padding) { + } + +}; + +} // namespace Ui diff --git a/Telegram/SourceFiles/ui/wrap/slide_wrap.cpp b/Telegram/SourceFiles/ui/wrap/slide_wrap.cpp new file mode 100644 index 000000000..4a7f01d87 --- /dev/null +++ b/Telegram/SourceFiles/ui/wrap/slide_wrap.cpp @@ -0,0 +1,135 @@ +/* +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-2017 John Preston, https://desktop.telegram.org +*/ +#include "ui/wrap/slide_wrap.h" + +namespace Ui { + +SlideWrap::SlideWrap( + QWidget *parent, + object_ptr child) +: SlideWrap( + parent, + std::move(child), + style::margins(), + st::slideWrapDuration) { +} + +SlideWrap::SlideWrap( + QWidget *parent, + object_ptr child, + const style::margins &padding) +: SlideWrap( + parent, + std::move(child), + padding, + st::slideWrapDuration) { +} + +SlideWrap::SlideWrap( + QWidget *parent, + object_ptr child, + int duration) +: SlideWrap(parent, std::move(child), style::margins(), duration) { +} + +SlideWrap::SlideWrap( + QWidget *parent, + object_ptr child, + const style::margins &padding, + int duration) +: Parent(parent, object_ptr>(parent, std::move(child), padding)) +, _duration(duration) { +} + +void SlideWrap::animationStep() { + auto newWidth = width(); + if (auto weak = wrapped()) { + auto margins = getMargins(); + weak->moveToLeft(margins.left(), margins.top()); + newWidth = weak->width(); + } + auto current = _slideAnimation.current(_visible ? 1. : 0.); + auto newHeight = wrapped() + ? (_slideAnimation.animating() + ? anim::interpolate(0, wrapped()->heightNoMargins(), current) + : (_visible ? wrapped()->height() : 0)) + : 0; + if (newWidth != width() || newHeight != height()) { + resize(newWidth, newHeight); + } + auto shouldBeHidden = !_visible && !_slideAnimation.animating(); + if (shouldBeHidden != isHidden()) { + setVisible(!shouldBeHidden); + if (shouldBeHidden) { + myEnsureResized(this); + } + } +} + +void SlideWrap::toggleAnimated(bool visible) { + if (_visible == visible) { + animationStep(); + return; + } + _visible = visible; + _slideAnimation.start( + [this] { animationStep(); }, + _visible ? 0. : 1., + _visible ? 1. : 0., + _duration, + anim::linear); + animationStep(); +} + +void SlideWrap::toggleFast(bool visible) { + _visible = visible; + finishAnimations(); +} + +void SlideWrap::finishAnimations() { + _slideAnimation.finish(); + animationStep(); +} + +QMargins SlideWrap::getMargins() const { + auto result = wrapped()->getMargins(); + return (animating() || !_visible) + ? QMargins(result.left(), 0, result.right(), 0) + : result; +} + +int SlideWrap::resizeGetHeight(int newWidth) { + if (wrapped()) { + wrapped()->resizeToWidth(newWidth); + } + return heightNoMargins(); +} + +void SlideWrap::wrappedSizeUpdated(QSize size) { + if (_slideAnimation.animating()) { + animationStep(); + } else if (_visible) { + resize(size); + } +} + +} // namespace Ui + diff --git a/Telegram/SourceFiles/ui/wrap/slide_wrap.h b/Telegram/SourceFiles/ui/wrap/slide_wrap.h new file mode 100644 index 000000000..1e2fc780f --- /dev/null +++ b/Telegram/SourceFiles/ui/wrap/slide_wrap.h @@ -0,0 +1,122 @@ +/* +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-2017 John Preston, https://desktop.telegram.org +*/ +#pragma once + +#include "ui/wrap/padding_wrap.h" + +namespace Ui { + +template +class SlideWrap; + +template <> +class SlideWrap : public Wrap> { + using Parent = Wrap>; + +public: + SlideWrap(QWidget *parent, object_ptr child); + SlideWrap( + QWidget *parent, + object_ptr child, + const style::margins &padding); + SlideWrap( + QWidget *parent, + object_ptr child, + int duration); + SlideWrap( + QWidget *parent, + object_ptr child, + const style::margins &padding, + int duration); + + void toggleAnimated(bool visible); + void toggleFast(bool visible); + + void showAnimated() { + toggleAnimated(true); + } + void hideAnimated() { + toggleAnimated(false); + } + + void showFast() { + toggleFast(true); + } + void hideFast() { + toggleFast(false); + } + + bool animating() const { + return _slideAnimation.animating(); + } + void finishAnimations(); + + QMargins getMargins() const override; + + bool isHiddenOrHiding() const { + return !_visible; + } + +protected: + int resizeGetHeight(int newWidth) override; + void wrappedSizeUpdated(QSize size) override; + +private: + void animationStep(); + + bool _visible = true; + Animation _slideAnimation; + int _duration = 0; + +}; + +template +class SlideWrap : public Wrap, SlideWrap> { + using Parent = Wrap, SlideWrap>; + +public: + SlideWrap(QWidget *parent, object_ptr child) + : Parent(parent, std::move(child)) { + } + SlideWrap( + QWidget *parent, + object_ptr child, + const style::margins &padding) + : Parent(parent, std::move(child), padding) { + } + SlideWrap( + QWidget *parent, + object_ptr child, + int duration) + : Parent(parent, std::move(child), duration) { + } + SlideWrap( + QWidget *parent, + object_ptr child, + const style::margins &padding, + int duration) + : Parent(parent, std::move(child), padding, duration) { + } + +}; + +} // namespace Ui + diff --git a/Telegram/SourceFiles/ui/wrap/vertical_layout.cpp b/Telegram/SourceFiles/ui/wrap/vertical_layout.cpp new file mode 100644 index 000000000..a56187070 --- /dev/null +++ b/Telegram/SourceFiles/ui/wrap/vertical_layout.cpp @@ -0,0 +1,188 @@ +/* +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-2017 John Preston, https://desktop.telegram.org +*/ +#include "ui/wrap/vertical_layout.h" + +namespace Ui { + +QMargins VerticalLayout::getMargins() const { + auto result = QMargins(); + if (!_rows.empty()) { + auto &top = _rows.front(); + auto topMargin = top.widget->getMargins().top(); + result.setTop( + qMax(topMargin - top.margin.top(), 0)); + auto &bottom = _rows.back(); + auto bottomMargin = bottom.widget->getMargins().bottom(); + result.setBottom( + qMax(bottomMargin - bottom.margin.bottom(), 0)); + for (auto &row : _rows) { + auto margins = row.widget->getMargins(); + result.setLeft(qMax( + margins.left() - row.margin.left(), + result.left())); + result.setRight(qMax( + margins.right() - row.margin.right(), + result.right())); + } + } + return result; +} + +int VerticalLayout::naturalWidth() const { + auto result = 0; + for (auto &row : _rows) { + auto natural = row.widget->naturalWidth(); + if (natural < 0) { + return natural; + } + accumulate_max(result, natural); + } + return result; +} + +int VerticalLayout::resizeGetHeight(int newWidth) { + auto margins = getMargins(); + auto result = 0; + for (auto &row : _rows) { + updateChildGeometry( + margins, + row.widget, + row.margin, + newWidth, + result); + result += row.margin.top() + + row.widget->heightNoMargins() + + row.margin.bottom(); + } + return height() - margins.top() - margins.bottom(); +} + +void VerticalLayout::visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) { + for (auto &row : _rows) { + setChildVisibleTopBottom( + row.widget, + visibleTop, + visibleBottom); + } +} + +void VerticalLayout::updateChildGeometry( + const style::margins &margins, + RpWidget *child, + const style::margins &margin, + int width, + int top) const { + auto availRowWidth = width + - margin.left() + - margin.right(); + child->resizeToNaturalWidth(availRowWidth); + child->moveToLeft( + margins.left() + margin.left(), + margins.top() + margin.top() + top, + width); +} + +RpWidget *VerticalLayout::addChild( + object_ptr child, + const style::margins &margin) { + if (auto weak = AttachParentChild(this, child)) { + _rows.push_back({ std::move(child), margin }); + auto margins = getMargins(); + updateChildGeometry( + margins, + weak, + margin, + width() - margins.left() - margins.right(), + height() - margins.top() - margins.bottom()); + weak->heightValue() + | rpl::on_next([this, weak](int) { + childHeightUpdated(weak); + }) + | rpl::on_done([this, weak] { + removeChild(weak); + }) + | rpl::start(lifetime()); + return weak; + } + return nullptr; +} + +void VerticalLayout::childHeightUpdated(RpWidget *child) { + auto it = base::find_if(_rows, [child](const Row &row) { + return (row.widget == child); + }); + + auto margins = getMargins(); + auto top = [&] { + if (it == _rows.begin()) { + return margins.top(); + } + auto prev = it - 1; + return prev->widget->bottomNoMargins() + prev->margin.bottom(); + }() - margins.top(); + for (auto end = _rows.end(); it != end; ++it) { + auto &row = *it; + auto margin = row.margin; + auto widget = row.widget.data(); + widget->moveToLeft( + margins.left() + margin.left(), + margins.top() + top + margin.top()); + top += margin.top() + + widget->heightNoMargins() + + margin.bottom(); + } + resize(width(), margins.top() + top + margins.bottom()); +} + +void VerticalLayout::removeChild(RpWidget *child) { + auto it = base::find_if(_rows, [child](const Row &row) { + return (row.widget == child); + }); + auto end = _rows.end(); + Assert(it != end); + + auto margins = getMargins(); + auto top = [&] { + if (it == _rows.begin()) { + return margins.top(); + } + auto prev = it - 1; + return prev->widget->bottomNoMargins() + prev->margin.bottom(); + }() - margins.top(); + for (auto next = it + 1; it != end; ++it) { + auto &row = *it; + auto margin = row.margin; + auto widget = row.widget.data(); + widget->moveToLeft( + margins.left() + margin.left(), + margins.top() + top + margin.top()); + top += margin.top() + + widget->heightNoMargins() + + margin.bottom(); + } + _rows.erase(it); + + resize(width(), margins.top() + top + margins.bottom()); +} + +} // namespace Ui diff --git a/Telegram/SourceFiles/ui/wrap/vertical_layout.h b/Telegram/SourceFiles/ui/wrap/vertical_layout.h new file mode 100644 index 000000000..a1f0cffdc --- /dev/null +++ b/Telegram/SourceFiles/ui/wrap/vertical_layout.h @@ -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-2017 John Preston, https://desktop.telegram.org +*/ +#pragma once + +#include "ui/rp_widget.h" + +namespace Ui { + +class VerticalLayout : public RpWidget { +public: + using RpWidget::RpWidget; + + template < + typename Widget, + typename = std::enable_if_t< + std::is_base_of_v>> + Widget *add( + object_ptr &&child, + const style::margins &margin = style::margins()) { + return static_cast(addChild( + std::move(child), + margin)); + } + + QMargins getMargins() const override; + int naturalWidth() const override; + +protected: + int resizeGetHeight(int newWidth) override; + void visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) override; + +private: + RpWidget *addChild( + object_ptr child, + const style::margins &margin); + void childHeightUpdated(RpWidget *child); + void removeChild(RpWidget *child); + void updateChildGeometry( + const style::margins &margins, + RpWidget *child, + const style::margins &margin, + int width, + int top) const; + + struct Row { + object_ptr widget; + style::margins margin; + }; + std::vector _rows; + +}; + +} // namespace Ui diff --git a/Telegram/SourceFiles/ui/wrap/wrap.h b/Telegram/SourceFiles/ui/wrap/wrap.h new file mode 100644 index 000000000..0f568cae7 --- /dev/null +++ b/Telegram/SourceFiles/ui/wrap/wrap.h @@ -0,0 +1,165 @@ +/* +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-2017 John Preston, https://desktop.telegram.org +*/ +#pragma once + +#include "ui/rp_widget.h" + +namespace Ui { + +template +class Wrap; + +namespace details { + +struct UnwrapHelper { + struct Large { + char data[2]; + }; + static char Check(...); + template + static Large Check(Wrap*); + template + static Large Check(const Wrap*); + + template + static constexpr bool Is() { + return sizeof(Check(std::declval())) + == sizeof(Large); + } + template + static auto Unwrap(Entity *entity, std::true_type) { + return entity + ? entity->entity() + : nullptr; + } + template + static Entity *Unwrap(Entity *entity, std::false_type) { + return entity; + } + template + static auto Unwrap(Entity *entity) { + return Unwrap( + entity, + std::integral_constant()>()); + } +}; + +} // namespace details + +template +class Wrap : public RpWidget { +public: + Wrap(QWidget *parent, object_ptr child); + + Widget *wrapped() { + return _wrapped; + } + const Widget *wrapped() const { + return _wrapped; + } + auto entity() { + return details::UnwrapHelper::Unwrap(wrapped()); + } + auto entity() const { + return details::UnwrapHelper::Unwrap(wrapped()); + } + + QMargins getMargins() const override { + if (auto weak = wrapped()) { + return weak->getMargins(); + } + return RpWidget::getMargins(); + } + int naturalWidth() const override { + if (auto weak = wrapped()) { + return weak->naturalWidth(); + } + return RpWidget::naturalWidth(); + } + +protected: + int resizeGetHeight(int newWidth) override { + if (auto weak = wrapped()) { + weak->resizeToWidth(newWidth); + return weak->heightNoMargins(); + } + return heightNoMargins(); + } + void visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) override { + setChildVisibleTopBottom( + wrapped(), + visibleTop, + visibleBottom); + } + virtual void wrappedSizeUpdated(QSize size) { + resize(size); + } + +private: + object_ptr _wrapped; + +}; + +template +Wrap::Wrap(QWidget *parent, object_ptr child) +: RpWidget(parent) +, _wrapped(std::move(child)) { + if (_wrapped) { + _wrapped->sizeValue() + | rpl::on_next([this](QSize &&value) { + wrappedSizeUpdated(value); + }) + | rpl::start(lifetime()); + AttachParentChild(this, _wrapped); + _wrapped->move(0, 0); + _wrapped->alive() + | rpl::on_done([this] { + _wrapped->setParent(nullptr); + _wrapped = nullptr; + delete this; + }) + | rpl::start(lifetime()); + } +} + +template +class Wrap : public ParentType { +public: + using ParentType::ParentType; + + Widget *wrapped() { + return static_cast(ParentType::wrapped()); + } + const Widget *wrapped() const { + return static_cast(ParentType::wrapped()); + } + auto entity() { + return details::UnwrapHelper::Unwrap(wrapped()); + } + auto entity() const { + return details::UnwrapHelper::Unwrap(wrapped()); + } + +}; + +} // namespace Ui diff --git a/Telegram/SourceFiles/window/player_wrap_widget.cpp b/Telegram/SourceFiles/window/player_wrap_widget.cpp index 1b81a818c..5c0419e06 100644 --- a/Telegram/SourceFiles/window/player_wrap_widget.cpp +++ b/Telegram/SourceFiles/window/player_wrap_widget.cpp @@ -24,20 +24,22 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org namespace Window { -PlayerWrapWidget::PlayerWrapWidget(QWidget *parent, base::lambda updateCallback) : Parent(parent - , object_ptr(parent) - , style::margins(0, 0, 0, 0) - , std::move(updateCallback)) { +PlayerWrapWidget::PlayerWrapWidget(QWidget *parent) +: Parent(parent, object_ptr(parent)) { + sizeValue() + | rpl::on_next([this](QSize &&size) { + updateShadowGeometry(size); + }) + | rpl::start(lifetime()); } -void PlayerWrapWidget::resizeEvent(QResizeEvent *e) { - updateShadowGeometry(); - Parent::resizeEvent(e); -} - -void PlayerWrapWidget::updateShadowGeometry() { +void PlayerWrapWidget::updateShadowGeometry(QSize size) { auto skip = Adaptive::OneColumn() ? 0 : st::lineWidth; - entity()->setShadowGeometryToLeft(skip, height() - st::lineWidth, width() - skip, st::lineWidth); + entity()->setShadowGeometryToLeft( + skip, + size.height() - st::lineWidth, + size.width() - skip, + st::lineWidth); } } // namespace Window diff --git a/Telegram/SourceFiles/window/player_wrap_widget.h b/Telegram/SourceFiles/window/player_wrap_widget.h index 4c0cd841d..2d8825ea6 100644 --- a/Telegram/SourceFiles/window/player_wrap_widget.h +++ b/Telegram/SourceFiles/window/player_wrap_widget.h @@ -1,6 +1,6 @@ #pragma once -#include "ui/effects/widget_slide_wrap.h" +#include "ui/wrap/slide_wrap.h" #include "media/player/media_player_widget.h" namespace Ui { @@ -9,14 +9,14 @@ class PlainShadow; namespace Window { -class PlayerWrapWidget : public Ui::WidgetSlideWrap { - using Parent = Ui::WidgetSlideWrap; +class PlayerWrapWidget : public Ui::SlideWrap { + using Parent = Ui::SlideWrap; public: - PlayerWrapWidget(QWidget *parent, base::lambda updateCallback); + PlayerWrapWidget(QWidget *parent); void updateAdaptiveLayout() { - updateShadowGeometry(); + updateShadowGeometry(size()); } void showShadow() { entity()->showShadow(); @@ -28,11 +28,8 @@ public: return qMax(height() - st::lineWidth, 0); } -protected: - void resizeEvent(QResizeEvent *e) override; - private: - void updateShadowGeometry(); + void updateShadowGeometry(QSize size); }; diff --git a/Telegram/SourceFiles/window/section_widget.h b/Telegram/SourceFiles/window/section_widget.h index 480ec69b3..cb82e7656 100644 --- a/Telegram/SourceFiles/window/section_widget.h +++ b/Telegram/SourceFiles/window/section_widget.h @@ -20,7 +20,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #pragma once -#include "ui/twidget.h" +#include "ui/rp_widget.h" #include "window/window_slide_animation.h" namespace Window { @@ -33,16 +33,22 @@ enum class Column { Third, }; -class AbstractSectionWidget : public TWidget, protected base::Subscriber { +class AbstractSectionWidget + : public Ui::RpWidget + , protected base::Subscriber { public: - AbstractSectionWidget(QWidget *parent, not_null controller) : TWidget(parent), _controller(controller) { + AbstractSectionWidget( + QWidget *parent, + not_null controller) + : RpWidget(parent) + , _controller(controller) { } // Float player interface. virtual bool wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn, Window::Column playerColumn) { return false; } - virtual QRect rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) { + virtual QRect rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const { return mapToGlobal(rect()); } diff --git a/Telegram/gyp/Telegram.gyp b/Telegram/gyp/Telegram.gyp index 6fa545e5d..4e514716d 100644 --- a/Telegram/gyp/Telegram.gyp +++ b/Telegram/gyp/Telegram.gyp @@ -112,6 +112,7 @@ '<@(qrc_files)', '<@(style_files)', '