From 5e7aa4ff815537971d456cc8d9b9500cd1b905cc Mon Sep 17 00:00:00 2001 From: John Preston Date: Sat, 16 Sep 2017 19:53:41 +0300 Subject: [PATCH] Move third column from HistoryWidget to MainWidget. --- Telegram/SourceFiles/apiwrap.h | 10 + Telegram/SourceFiles/auth_session.cpp | 25 +- Telegram/SourceFiles/auth_session.h | 16 +- .../SourceFiles/boxes/sticker_set_box.cpp | 14 +- Telegram/SourceFiles/boxes/sticker_set_box.h | 11 +- Telegram/SourceFiles/boxes/stickers_box.cpp | 2 +- .../chat_helpers/emoji_list_widget.cpp | 10 +- .../chat_helpers/emoji_list_widget.h | 2 +- .../chat_helpers/gifs_list_widget.cpp | 20 +- .../chat_helpers/gifs_list_widget.h | 2 +- .../SourceFiles/chat_helpers/stickers.cpp | 2 +- .../chat_helpers/stickers_list_widget.cpp | 21 +- .../chat_helpers/stickers_list_widget.h | 2 +- .../SourceFiles/chat_helpers/tabbed_panel.cpp | 23 +- .../SourceFiles/chat_helpers/tabbed_panel.h | 7 +- .../chat_helpers/tabbed_section.cpp | 61 +- .../SourceFiles/chat_helpers/tabbed_section.h | 51 +- .../chat_helpers/tabbed_selector.cpp | 44 +- .../chat_helpers/tabbed_selector.h | 13 +- .../SourceFiles/dialogs/dialogs_widget.cpp | 4 +- Telegram/SourceFiles/dialogs/dialogs_widget.h | 4 +- Telegram/SourceFiles/facades.cpp | 14 +- Telegram/SourceFiles/facades.h | 8 +- Telegram/SourceFiles/history/history.style | 2 + .../history/history_admin_log_section.cpp | 13 +- .../history/history_admin_log_section.h | 10 +- .../SourceFiles/history/history_widget.cpp | 381 +++-------- Telegram/SourceFiles/history/history_widget.h | 22 +- Telegram/SourceFiles/info/info_layer_wrap.cpp | 2 +- .../info/info_media_inner_widget.cpp | 8 - Telegram/SourceFiles/info/info_memento.cpp | 24 +- Telegram/SourceFiles/info/info_memento.h | 2 + .../SourceFiles/info/info_narrow_wrap.cpp | 14 +- Telegram/SourceFiles/info/info_narrow_wrap.h | 9 +- Telegram/SourceFiles/info/info_side_wrap.cpp | 29 +- Telegram/SourceFiles/info/info_side_wrap.h | 12 +- Telegram/SourceFiles/mainwidget.cpp | 599 ++++++++++++------ Telegram/SourceFiles/mainwidget.h | 45 +- Telegram/SourceFiles/mainwindow.cpp | 2 +- Telegram/SourceFiles/overviewwidget.cpp | 8 +- Telegram/SourceFiles/overviewwidget.h | 4 +- .../profile/profile_block_channel_members.cpp | 2 +- .../profile/profile_block_settings.cpp | 2 +- .../profile/profile_block_shared_media.cpp | 2 +- .../profile/profile_common_groups_section.cpp | 12 +- .../profile/profile_common_groups_section.h | 10 +- .../SourceFiles/profile/profile_cover.cpp | 2 +- .../profile/profile_inner_widget.cpp | 2 +- .../profile/profile_section_memento.cpp | 6 +- .../profile/profile_section_memento.h | 6 +- .../SourceFiles/profile/profile_widget.cpp | 4 +- Telegram/SourceFiles/profile/profile_widget.h | 4 +- Telegram/SourceFiles/ui/animation.h | 5 + Telegram/SourceFiles/ui/twidget.cpp | 2 - Telegram/SourceFiles/window/main_window.h | 6 +- Telegram/SourceFiles/window/section_memento.h | 2 + .../SourceFiles/window/section_widget.cpp | 7 +- Telegram/SourceFiles/window/section_widget.h | 10 +- .../SourceFiles/window/top_bar_widget.cpp | 66 +- Telegram/SourceFiles/window/top_bar_widget.h | 7 +- Telegram/SourceFiles/window/window.style | 22 +- .../SourceFiles/window/window_controller.cpp | 156 ++++- .../SourceFiles/window/window_controller.h | 52 +- 63 files changed, 1187 insertions(+), 752 deletions(-) diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index 1ea453c1d..558903b68 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -20,6 +20,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #pragma once +#include #include "base/timer.h" #include "core/single_timer.h" #include "mtproto/sender.h" @@ -132,6 +133,13 @@ public: not_null user, PhotoId afterId); + void stickerSetInstalled(uint64 setId) { + _stickerSetInstalled.fire_copy(setId); + } + rpl::producer stickerSetInstalled() const { + return _stickerSetInstalled.events(); + } + ~ApiWrap(); private: @@ -262,4 +270,6 @@ private: base::Observable _fullPeerUpdated; + rpl::event_stream _stickerSetInstalled; + }; diff --git a/Telegram/SourceFiles/auth_session.cpp b/Telegram/SourceFiles/auth_session.cpp index aa93cc44a..f01d15fc7 100644 --- a/Telegram/SourceFiles/auth_session.cpp +++ b/Telegram/SourceFiles/auth_session.cpp @@ -71,6 +71,7 @@ QByteArray AuthSessionData::serialize() const { for (auto peerId : _variables.groupStickersSectionHidden) { stream << quint64(peerId); } + stream << qint32(_variables.thirdSectionInfoEnabled ? 1 : 0); } return result; } @@ -89,7 +90,8 @@ void AuthSessionData::constructFromSerialized(const QByteArray &serialized) { qint32 floatPlayerColumn = static_cast(Window::Column::Second); qint32 floatPlayerCorner = static_cast(RectPart::TopRight); QMap soundOverrides; - OrderedSet groupStickersSectionHidden; + base::flat_set groupStickersSectionHidden; + qint32 thirdSectionInfoEnabled = 0; stream >> selectorTab; stream >> lastSeenWarningSeen; if (!stream.atEnd()) { @@ -123,6 +125,9 @@ void AuthSessionData::constructFromSerialized(const QByteArray &serialized) { } } } + if (!stream.atEnd()) { + stream >> thirdSectionInfoEnabled; + } if (stream.status() != QDataStream::Ok) { LOG(("App Error: Bad data for AuthSessionData::constructFromSerialized()")); return; @@ -152,6 +157,24 @@ void AuthSessionData::constructFromSerialized(const QByteArray &serialized) { case RectPart::BottomRight: _variables.floatPlayerCorner = uncheckedCorner; break; } _variables.groupStickersSectionHidden = std::move(groupStickersSectionHidden); + _variables.thirdSectionInfoEnabled = thirdSectionInfoEnabled; +} + +void AuthSessionData::setTabbedSelectorSectionEnabled(bool enabled) { + _variables.tabbedSelectorSectionEnabled = enabled; + if (enabled) { + setThirdSectionInfoEnabled(false); + } +} + +void AuthSessionData::setThirdSectionInfoEnabled(bool enabled) { + if (_variables.thirdSectionInfoEnabled != enabled) { + _variables.thirdSectionInfoEnabled = enabled; + if (enabled) { + setTabbedSelectorSectionEnabled(false); + } + _thirdSectionInfoEnabledValue.fire_copy(enabled); + } } QString AuthSessionData::getSoundPath(const QString &key) const { diff --git a/Telegram/SourceFiles/auth_session.h b/Telegram/SourceFiles/auth_session.h index 8f9134b0c..16758bb6b 100644 --- a/Telegram/SourceFiles/auth_session.h +++ b/Telegram/SourceFiles/auth_session.h @@ -20,6 +20,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #pragma once +#include #include "base/timer.h" namespace Storage { @@ -100,8 +101,14 @@ public: bool tabbedSelectorSectionEnabled() const { return _variables.tabbedSelectorSectionEnabled; } - void setTabbedSelectorSectionEnabled(bool enabled) { - _variables.tabbedSelectorSectionEnabled = enabled; + void setTabbedSelectorSectionEnabled(bool enabled); + bool thirdSectionInfoEnabled() const { + return _variables.thirdSectionInfoEnabled; + } + void setThirdSectionInfoEnabled(bool enabled); + rpl::producer thirdSectionInfoEnabledValue() const { + return _thirdSectionInfoEnabledValue.events_starting_with( + thirdSectionInfoEnabled()); } void setLastTimeVideoPlayedAt(TimeMs time) { _lastTimeVideoPlayedAt = time; @@ -155,7 +162,8 @@ private: QMap soundOverrides; Window::Column floatPlayerColumn; RectPart floatPlayerCorner; - OrderedSet groupStickersSectionHidden; + base::flat_set groupStickersSectionHidden; + bool thirdSectionInfoEnabled = false; }; base::Variable _contactsLoaded = { false }; @@ -167,6 +175,8 @@ private: base::Observable> _repaintLogEntry; base::Observable _pendingHistoryResize; base::Observable _queryItemVisibility; + rpl::event_stream _thirdSectionInfoEnabledValue; + Variables _variables; TimeMs _lastTimeVideoPlayedAt = 0; diff --git a/Telegram/SourceFiles/boxes/sticker_set_box.cpp b/Telegram/SourceFiles/boxes/sticker_set_box.cpp index ea9afe17d..84605f166 100644 --- a/Telegram/SourceFiles/boxes/sticker_set_box.cpp +++ b/Telegram/SourceFiles/boxes/sticker_set_box.cpp @@ -56,12 +56,12 @@ void StickerSetBox::prepare() { onUpdateButtons(); connect(_inner, SIGNAL(updateButtons()), this, SLOT(onUpdateButtons())); - connect(_inner, SIGNAL(installed(uint64)), this, SLOT(onInstalled(uint64))); -} - -void StickerSetBox::onInstalled(uint64 setId) { - emit installed(setId); - closeBox(); + _inner->setInstalled() + | rpl::on_next([this](auto &&setId) { + Auth().api().stickerSetInstalled(setId); + closeBox(); + }) + | rpl::start(lifetime()); } void StickerSetBox::onAddStickers() { @@ -250,7 +250,7 @@ void StickerSetBox::Inner::installDone(const MTPmessages_StickerSetInstallResult Local::writeInstalledStickers(); Auth().data().stickersUpdated().notify(true); } - emit installed(_setId); + _setInstalled.fire_copy(_setId); } bool StickerSetBox::Inner::installFail(const RPCError &error) { diff --git a/Telegram/SourceFiles/boxes/sticker_set_box.h b/Telegram/SourceFiles/boxes/sticker_set_box.h index 979daa55a..9e2259e15 100644 --- a/Telegram/SourceFiles/boxes/sticker_set_box.h +++ b/Telegram/SourceFiles/boxes/sticker_set_box.h @@ -35,9 +35,6 @@ class StickerSetBox : public BoxContent, public RPCSender { public: StickerSetBox(QWidget*, const MTPInputStickerSet &set); -signals: - void installed(uint64 id); - protected: void prepare() override; @@ -48,8 +45,6 @@ private slots: void onShareStickers(); void onUpdateButtons(); - void onInstalled(uint64 id); - private: void updateButtons(); @@ -74,6 +69,9 @@ public: QString shortName() const; void install(); + rpl::producer setInstalled() const { + return _setInstalled.events(); + } ~Inner(); @@ -89,7 +87,6 @@ private slots: signals: void updateButtons(); - void installed(uint64 id); private: void updateSelected(); @@ -127,4 +124,6 @@ private: QTimer _previewTimer; int _previewShown = -1; + rpl::event_stream _setInstalled; + }; diff --git a/Telegram/SourceFiles/boxes/stickers_box.cpp b/Telegram/SourceFiles/boxes/stickers_box.cpp index 4c463ef2a..64855d810 100644 --- a/Telegram/SourceFiles/boxes/stickers_box.cpp +++ b/Telegram/SourceFiles/boxes/stickers_box.cpp @@ -1094,7 +1094,7 @@ void StickersBox::Inner::saveGroupSet() { auto newId = (_megagroupSetInput.type() == mtpc_inputStickerSetID) ? _megagroupSetInput.c_inputStickerSetID().vid.v : 0; if (newId != oldId) { Auth().api().setGroupStickerSet(_megagroupSet, _megagroupSetInput); - App::main()->onStickersInstalled(Stickers::MegagroupSetId); + Auth().api().stickerSetInstalled(Stickers::MegagroupSetId); } } diff --git a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp index fe04b1fba..2ad4e20d6 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp @@ -304,7 +304,7 @@ void EmojiColorPicker::drawVariant(Painter &p, int variant) { EmojiListWidget::EmojiListWidget(QWidget *parent, not_null controller) : Inner(parent, controller) , _picker(this) { - resize(st::emojiPanWidth - st::emojiScroll.width - st::buttonRadius, countHeight()); + updateSize(); setMouseTracking(true); setAttribute(Qt::WA_OpaquePaintEvent); @@ -381,7 +381,7 @@ EmojiListWidget::SectionInfo EmojiListWidget::sectionInfoByOffset(int yOffset) c return result; } -int EmojiListWidget::countHeight() { +int EmojiListWidget::countDesiredHeight() { return sectionInfo(kEmojiSectionCount - 1).rowsBottom + st::emojiPanPadding; } @@ -648,11 +648,7 @@ void EmojiListWidget::refreshRecent() { clearSelection(); _emoji[0] = Ui::Emoji::GetSection(Section::Recent); _counts[0] = _emoji[0].size(); - auto h = countHeight(); - if (h != height()) { - resize(width(), h); - update(); - } + updateSize(); } bool EmojiListWidget::event(QEvent *e) { diff --git a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h index a698e26e9..9caedb39d 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h +++ b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h @@ -126,7 +126,7 @@ protected: TabbedSelector::InnerFooter *getFooter() const override; void processHideFinished() override; - int countHeight() override; + int countDesiredHeight() override; private: class Footer; diff --git a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp index 5bec04f60..65c9f338c 100644 --- a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp @@ -122,7 +122,7 @@ void GifsListWidget::Footer::processPanelHideFinished() { GifsListWidget::GifsListWidget(QWidget *parent, not_null controller) : Inner(parent, controller) , _section(Section::Gifs) { - resize(st::emojiPanWidth - st::emojiScroll.width - st::buttonRadius, countHeight()); + updateSize(); setMouseTracking(true); setAttribute(Qt::WA_OpaquePaintEvent); @@ -174,17 +174,12 @@ void GifsListWidget::checkLoadMore() { } } -int GifsListWidget::countHeight() { - auto visibleHeight = getVisibleBottom() - getVisibleTop(); - if (visibleHeight <= 0) { - visibleHeight = st::emojiPanMaxHeight - st::emojiCategory.height; - } - auto minimalLastHeight = (visibleHeight - st::stickerPanPadding); +int GifsListWidget::countDesiredHeight() { auto result = st::stickerPanPadding; for (int i = 0, l = _rows.count(); i < l; ++i) { result += _rows[i].height; } - return qMax(minimalLastHeight, result) + st::stickerPanPadding; + return result + st::stickerPanPadding; } GifsListWidget::~GifsListWidget() { @@ -475,11 +470,7 @@ void GifsListWidget::refreshSavedGifs() { } deleteUnusedGifLayouts(); - auto newHeight = countHeight(); - if (newHeight != height()) { - resize(width(), newHeight); - } - + updateSize(); update(); } @@ -642,8 +633,7 @@ int GifsListWidget::refreshInlineRows(const InlineCacheEntry *entry, bool result inlineRowFinalize(row, sumWidth, true); } - int32 h = countHeight(); - if (h != height()) resize(width(), h); + updateSize(); update(); _lastMousePos = QCursor::pos(); diff --git a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h index 58bcef818..169f4bc97 100644 --- a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h +++ b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h @@ -82,7 +82,7 @@ protected: TabbedSelector::InnerFooter *getFooter() const override; void processHideFinished() override; void processPanelHideFinished() override; - int countHeight() override; + int countDesiredHeight() override; private slots: void onPreview(); diff --git a/Telegram/SourceFiles/chat_helpers/stickers.cpp b/Telegram/SourceFiles/chat_helpers/stickers.cpp index 45e1673fd..f2bcc85d3 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers.cpp @@ -262,7 +262,7 @@ void SetIsFaved(not_null document, base::optionalonStickersInstalled(FavedSetId); + Auth().api().stickerSetInstalled(FavedSetId); } void RequestSetToPushFaved(not_null document) { diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp index e48b907ed..4b32ea3db 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp @@ -440,7 +440,7 @@ StickersListWidget::StickersListWidget(QWidget *parent, not_nullwidth(_addText)) , _settings(this, lang(lng_stickers_you_have)) { - resize(st::emojiPanWidth - st::emojiScroll.width - st::buttonRadius, countHeight()); + updateSize(); setMouseTracking(true); setAttribute(Qt::WA_OpaquePaintEvent); @@ -559,11 +559,8 @@ StickersListWidget::SectionInfo StickersListWidget::sectionInfoByOffset(int yOff return result; } -int StickersListWidget::countHeight() { - auto visibleHeight = getVisibleBottom() - getVisibleTop(); - if (visibleHeight <= 0) { - visibleHeight = st::emojiPanMaxHeight - st::emojiCategory.height; - } +int StickersListWidget::countDesiredHeight() { + auto visibleHeight = minimalHeight(); auto minimalLastHeight = (visibleHeight - st::stickerPanPadding); auto countResult = [this, minimalLastHeight] { if (_section == Section::Featured) { @@ -1154,10 +1151,7 @@ void StickersListWidget::refreshStickers() { appendSet(_featuredSets, setId, AppendSkip::Installed); } - auto newHeight = countHeight(); - if (newHeight != height()) { - resize(width(), newHeight); - } + updateSize(); if (_footer) { _footer->refreshIcons(ValidateIconAnimations::None); @@ -1283,12 +1277,7 @@ void StickersListWidget::refreshRecentStickers(bool performResize) { } if (performResize && (_section == Section::Stickers || _section == Section::Featured)) { - int32 h = countHeight(); - if (h != height()) { - resize(width(), h); - update(); - } - + updateSize(); updateSelected(); } } diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h index 84c41c4c7..7113689a5 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h @@ -79,7 +79,7 @@ protected: TabbedSelector::InnerFooter *getFooter() const override; void processHideFinished() override; void processPanelHideFinished() override; - int countHeight() override; + int countDesiredHeight() override; private slots: void onSettings(); diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp b/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp index 128531b2d..921c23ca9 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp +++ b/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp @@ -34,10 +34,20 @@ constexpr auto kDelayedHideTimeoutMs = 3000; } // namespace -TabbedPanel::TabbedPanel(QWidget *parent, not_null controller) : TabbedPanel(parent, controller, object_ptr(nullptr, controller)) { +TabbedPanel::TabbedPanel( + QWidget *parent, + not_null controller) +: TabbedPanel( + parent, + controller, + object_ptr(nullptr, controller)) { } -TabbedPanel::TabbedPanel(QWidget *parent, not_null controller, object_ptr selector) : TWidget(parent) +TabbedPanel::TabbedPanel( + QWidget *parent, + not_null controller, + object_ptr selector) +: RpWidget(parent) , _controller(controller) , _selector(std::move(selector)) { _selector->setParent(this); @@ -52,6 +62,9 @@ TabbedPanel::TabbedPanel(QWidget *parent, not_null controll _controller->disableGifPauseReason(Window::GifPauseReason::SavedGifs); } }); + _selector->showRequests() + | rpl::on_next([this](auto&&) { showFromSelector(); }) + | rpl::start(lifetime()); resize(QRect(0, 0, st::emojiPanWidth, st::emojiPanMaxHeight).marginsAdded(innerPadding()).size()); @@ -376,11 +389,7 @@ bool TabbedPanel::eventFilter(QObject *obj, QEvent *e) { return false; } -void TabbedPanel::stickersInstalled(uint64 setId) { - if (isDestroying()) { - return; - } - _selector->stickersInstalled(setId); +void TabbedPanel::showFromSelector() { if (isHidden()) { moveByBottom(); startShowAnimation(); diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_panel.h b/Telegram/SourceFiles/chat_helpers/tabbed_panel.h index 32438d302..42e253f64 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_panel.h +++ b/Telegram/SourceFiles/chat_helpers/tabbed_panel.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 "base/timer.h" namespace Window { @@ -35,7 +35,7 @@ namespace ChatHelpers { class TabbedSelector; -class TabbedPanel : public TWidget { +class TabbedPanel : public Ui::RpWidget{ Q_OBJECT public: @@ -51,8 +51,6 @@ public: return _hiding || _hideTimer.isActive(); } - void stickersInstalled(uint64 setId); - bool overlaps(const QRect &globalRect) const; void showAnimated(); @@ -79,6 +77,7 @@ private: bool isDestroying() const { return !_selector; } + void showFromSelector(); style::margins innerPadding() const; diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_section.cpp b/Telegram/SourceFiles/chat_helpers/tabbed_section.cpp index 3c84f57ef..bf76b8810 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_section.cpp +++ b/Telegram/SourceFiles/chat_helpers/tabbed_section.cpp @@ -25,11 +25,49 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org namespace ChatHelpers { -TabbedSection::TabbedSection(QWidget *parent, not_null controller) : TabbedSection(parent, controller, object_ptr(this, controller)) { +TabbedMemento::TabbedMemento( + object_ptr selector, + base::lambda)> returnMethod) +: _selector(std::move(selector)) +, _returnMethod(std::move(returnMethod)) { } -TabbedSection::TabbedSection(QWidget *parent, not_null controller, object_ptr selector) : Window::AbstractSectionWidget(parent, controller) -, _selector(std::move(selector)) { +object_ptr TabbedMemento::createWidget( + QWidget *parent, + not_null controller, + Window::Column column, + const QRect &geometry) { + return object_ptr( + parent, + controller, + std::move(_selector), + std::move(_returnMethod)); +} + +TabbedMemento::~TabbedMemento() { + if (_returnMethod && _selector) { + _returnMethod(std::move(_selector)); + } +} + +TabbedSection::TabbedSection( + QWidget *parent, + not_null controller) +: TabbedSection( + parent, + controller, + object_ptr(this, controller), + base::lambda)>()) { +} + +TabbedSection::TabbedSection( + QWidget *parent, + not_null controller, + object_ptr selector, + base::lambda)> returnMethod) +: Window::SectionWidget(parent, controller) +, _selector(std::move(selector)) +, _returnMethod(std::move(returnMethod)) { resize(st::emojiPanWidth, st::emojiPanMaxHeight); _selector->setParent(this); @@ -68,17 +106,24 @@ object_ptr TabbedSection::takeSelector() { QPointer TabbedSection::getSelector() const { return _selector.data(); } - -void TabbedSection::stickersInstalled(uint64 setId) { - _selector->stickersInstalled(setId); +bool TabbedSection::showInternal( + not_null memento) { + return false; } -bool TabbedSection::wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn, Window::Column playerColumn) { +bool TabbedSection::wheelEventFromFloatPlayer(QEvent *e) { return _selector->wheelEventFromFloatPlayer(e); } -QRect TabbedSection::rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const { +QRect TabbedSection::rectForFloatPlayer() const { return _selector->rectForFloatPlayer(); } +TabbedSection::~TabbedSection() { + beforeHiding(); + if (_returnMethod) { + _returnMethod(takeSelector()); + } +} + } // namespace ChatHelpers diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_section.h b/Telegram/SourceFiles/chat_helpers/tabbed_section.h index 008e0f8ea..345ab5059 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_section.h +++ b/Telegram/SourceFiles/chat_helpers/tabbed_section.h @@ -21,15 +21,42 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #pragma once #include "window/section_widget.h" +#include "window/section_memento.h" namespace ChatHelpers { class TabbedSelector; -class TabbedSection : public Window::AbstractSectionWidget { +class TabbedMemento : public Window::SectionMemento { public: - TabbedSection(QWidget *parent, not_null controller); - TabbedSection(QWidget *parent, not_null controller, object_ptr selector); + TabbedMemento( + object_ptr selector, + base::lambda)> returnMethod); + + object_ptr createWidget( + QWidget *parent, + not_null controller, + Window::Column column, + const QRect &geometry) override; + + ~TabbedMemento(); + +private: + object_ptr _selector; + base::lambda)> _returnMethod; + +}; + +class TabbedSection : public Window::SectionWidget { +public: + TabbedSection( + QWidget *parent, + not_null controller); + TabbedSection( + QWidget *parent, + not_null controller, + object_ptr selector, + base::lambda)> returnMethod); void beforeHiding(); void afterShown(); @@ -40,18 +67,28 @@ public: object_ptr takeSelector(); QPointer getSelector() const; - void stickersInstalled(uint64 setId); - + bool showInternal( + not_null memento) override; + bool forceAnimateBack() const override { + return true; + } // Float player interface. - bool wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn, Window::Column playerColumn) override; - QRect rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const override; + bool wheelEventFromFloatPlayer(QEvent *e) override; + QRect rectForFloatPlayer() const override; + + ~TabbedSection(); protected: void resizeEvent(QResizeEvent *e) override; + void showFinishedHook() override { + afterShown(); + } + private: object_ptr _selector; base::lambda _cancelledCallback; + base::lambda)> _returnMethod; }; diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp b/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp index 0cdfb7bc6..3ecea89aa 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp +++ b/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp @@ -346,6 +346,14 @@ TabbedSelector::TabbedSelector(QWidget *parent, not_null co } })); + Auth().api().stickerSetInstalled() + | rpl::on_next([this](uint64 setId) { + _tabsSlider->setActiveSection(static_cast(SelectorTab::Stickers)); + stickers()->showStickerSet(setId); + _showRequests.fire({}); + }) + | rpl::start(lifetime()); + // setAttribute(Qt::WA_AcceptTouchEvents); setAttribute(Qt::WA_OpaquePaintEvent, false); showAll(); @@ -356,9 +364,11 @@ void TabbedSelector::resizeEvent(QResizeEvent *e) { if (e->oldSize().height() > height()) { _scroll->resize(_scroll->width(), contentHeight); auto scrollTop = _scroll->scrollTop(); + currentTab()->widget()->setMinimalHeight(contentHeight); currentTab()->widget()->setVisibleTopBottom(scrollTop, scrollTop + contentHeight); } else { auto scrollTop = _scroll->scrollTop(); + currentTab()->widget()->setMinimalHeight(contentHeight); currentTab()->widget()->setVisibleTopBottom(scrollTop, scrollTop + contentHeight); _scroll->resize(_scroll->width(), contentHeight); } @@ -514,11 +524,6 @@ void TabbedSelector::afterShown() { } } -void TabbedSelector::stickersInstalled(uint64 setId) { - _tabsSlider->setActiveSection(static_cast(SelectorTab::Stickers)); - stickers()->showStickerSet(setId); -} - void TabbedSelector::showMegagroupSet(ChannelData *megagroup) { stickers()->showMegagroupSet(megagroup); } @@ -702,15 +707,36 @@ TabbedSelector::Inner::Inner(QWidget *parent, not_null cont } void TabbedSelector::Inner::visibleTopBottomUpdated(int visibleTop, int visibleBottom) { - auto oldVisibleHeight = getVisibleBottom() - getVisibleTop(); _visibleTop = visibleTop; _visibleBottom = visibleBottom; - auto visibleHeight = getVisibleBottom() - getVisibleTop(); - if (visibleHeight != oldVisibleHeight) { - resize(st::emojiPanWidth - st::emojiScroll.width - st::buttonRadius, countHeight()); +} + +void TabbedSelector::Inner::setMinimalHeight(int newMinimalHeight) { + if (_minimalHeight != newMinimalHeight) { + _minimalHeight = newMinimalHeight; + updateSize(); } } +void TabbedSelector::Inner::updateSize() { + auto width = st::emojiPanWidth + - st::emojiScroll.width + - st::buttonRadius; + auto height = qMax(countDesiredHeight(), minimalHeight()); + auto newSize = QSize(width, height); + if (size() != newSize) { + resize(newSize); + update(); + } +} + +int TabbedSelector::Inner::minimalHeight() const { + auto result = _minimalHeight; + return (_minimalHeight > 0) + ? _minimalHeight + : (st::emojiPanMaxHeight - st::emojiCategory.height); +} + void TabbedSelector::Inner::hideFinished() { processHideFinished(); if (auto footer = getFooter()) { diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_selector.h b/Telegram/SourceFiles/chat_helpers/tabbed_selector.h index 4bb277fca..26a9f8f7a 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_selector.h +++ b/Telegram/SourceFiles/chat_helpers/tabbed_selector.h @@ -60,7 +60,6 @@ public: void setRoundRadius(int radius); void refreshStickers(); - void stickersInstalled(uint64 setId); void showMegagroupSet(ChannelData *megagroup); void setCurrentPeer(PeerData *peer); @@ -88,6 +87,10 @@ public: bool wheelEventFromFloatPlayer(QEvent *e); QRect rectForFloatPlayer() const; + rpl::producer<> showRequests() const { + return _showRequests.events(); + } + ~TabbedSelector(); class Inner; @@ -199,6 +202,8 @@ private: base::lambda _afterShownCallback; base::lambda _beforeHidingCallback; + rpl::event_stream<> _showRequests; + }; class TabbedSelector::Inner : public TWidget { @@ -213,6 +218,7 @@ public: int getVisibleBottom() const { return _visibleBottom; } + void setMinimalHeight(int newMinimalHeight); virtual void refreshRecent() = 0; virtual void preloadImages() { @@ -236,12 +242,14 @@ protected: void visibleTopBottomUpdated( int visibleTop, int visibleBottom) override; + void updateSize(); + int minimalHeight() const; not_null controller() const { return _controller; } - virtual int countHeight() = 0; + virtual int countDesiredHeight() = 0; virtual InnerFooter *getFooter() const = 0; virtual void processHideFinished() { } @@ -253,6 +261,7 @@ private: int _visibleTop = 0; int _visibleBottom = 0; + int _minimalHeight = 0; }; diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index f77329621..1fb4c63db 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -267,11 +267,11 @@ void DialogsWidget::showAnimated(Window::SlideDirection direction, const Window: _a_show.start([this] { animationCallback(); }, 0., 1., st::slideDuration, Window::SlideAnimation::transition()); } -bool DialogsWidget::wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn, Window::Column playerColumn) { +bool DialogsWidget::wheelEventFromFloatPlayer(QEvent *e) { return _scroll->viewportEvent(e); } -QRect DialogsWidget::rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const { +QRect DialogsWidget::rectForFloatPlayer() const { return mapToGlobal(_scroll->geometry()); } diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.h b/Telegram/SourceFiles/dialogs/dialogs_widget.h index 3a2342017..fbdac2f87 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.h @@ -98,8 +98,8 @@ public: void onSearchMore(); // Float player interface. - bool wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn, Window::Column playerColumn) override; - QRect rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const override; + bool wheelEventFromFloatPlayer(QEvent *e) override; + QRect rectForFloatPlayer() 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 91948f390..d6dc3e432 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -262,17 +262,9 @@ void autoplayMediaInlineAsync(const FullMsgId &msgId) { } void showPeerProfile(const PeerId &peer) { - //if (auto main = App::main()) { - // main->showWideSection(Profile::SectionMemento(App::peer(peer))); - //} - - if (auto window = App::wnd()) { - auto memento = Info::Memento(peer); - if (auto layer = memento.createLayer(window->controller())) { - window->controller()->showSpecialLayer(std::move(layer)); - } else { - App::main()->showWideSection(std::move(memento)); - } + if (auto main = App::main()) { +// main->showSection(Profile::SectionMemento(App::peer(peer))); + main->showSection(Info::Memento(peer), anim::type::normal); } } diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index f3a2f2527..619f336e1 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -238,6 +238,7 @@ enum class WindowLayout { OneColumn, SmallColumn, Normal, + ThreeColumn, }; enum class ChatLayout { @@ -424,8 +425,13 @@ inline bool Normal() { return Global::AdaptiveWindowLayout() == WindowLayout::Normal; } +inline bool ThreeColumn() { + return Global::AdaptiveWindowLayout() == WindowLayout::ThreeColumn; +} + inline bool ChatNormal() { - return !Global::AdaptiveForWide() || (Global::AdaptiveChatLayout() == ChatLayout::Normal); + return !Global::AdaptiveForWide() + || (Global::AdaptiveChatLayout() == ChatLayout::Normal); } inline bool ChatWide() { diff --git a/Telegram/SourceFiles/history/history.style b/Telegram/SourceFiles/history/history.style index db49b1f48..433f02942 100644 --- a/Telegram/SourceFiles/history/history.style +++ b/Telegram/SourceFiles/history/history.style @@ -22,6 +22,8 @@ using "basic.style"; using "dialogs/dialogs.style"; using "ui/widgets/widgets.style"; +historyMinimalWidth: 380px; + historyScroll: ScrollArea(defaultScrollArea) { bg: historyScrollBg; bgOver: historyScrollBgOver; diff --git a/Telegram/SourceFiles/history/history_admin_log_section.cpp b/Telegram/SourceFiles/history/history_admin_log_section.cpp index 17a4db701..360296675 100644 --- a/Telegram/SourceFiles/history/history_admin_log_section.cpp +++ b/Telegram/SourceFiles/history/history_admin_log_section.cpp @@ -88,7 +88,14 @@ private: }; -object_ptr SectionMemento::createWidget(QWidget *parent, not_null controller, const QRect &geometry) { +object_ptr SectionMemento::createWidget( + QWidget *parent, + not_null controller, + Window::Column column, + const QRect &geometry) { + if (column == Window::Column::Third) { + return nullptr; + } auto result = object_ptr(parent, controller, _channel); result->setInternalState(geometry, this); return std::move(result); @@ -427,11 +434,11 @@ void Widget::showFinishedHook() { _fixedBar->setAnimatingMode(false); } -bool Widget::wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn, Window::Column playerColumn) { +bool Widget::wheelEventFromFloatPlayer(QEvent *e) { return _scroll->viewportEvent(e); } -QRect Widget::rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const { +QRect Widget::rectForFloatPlayer() 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 d9d0c7668..b0de0475d 100644 --- a/Telegram/SourceFiles/history/history_admin_log_section.h +++ b/Telegram/SourceFiles/history/history_admin_log_section.h @@ -101,8 +101,8 @@ public: void setInternalState(const QRect &geometry, not_null memento); // Float player interface. - bool wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn, Window::Column playerColumn) override; - QRect rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const override; + bool wheelEventFromFloatPlayer(QEvent *e) override; + QRect rectForFloatPlayer() const override; void applyFilter(FilterValue &&value); @@ -136,7 +136,11 @@ public: SectionMemento(not_null channel) : _channel(channel) { } - object_ptr createWidget(QWidget *parent, not_null controller, const QRect &geometry) override; + object_ptr createWidget( + QWidget *parent, + not_null controller, + Window::Column column, + const QRect &geometry) override; not_null getChannel() const { return _channel; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index d3846f455..0741eb3b1 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -47,8 +47,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "profile/profile_block_group_members.h" #include "core/click_handler_types.h" #include "chat_helpers/tabbed_panel.h" -#include "chat_helpers/tabbed_section.h" #include "chat_helpers/tabbed_selector.h" +#include "chat_helpers/tabbed_section.h" #include "chat_helpers/bot_keyboard.h" #include "chat_helpers/message_field.h" #include "lang/lang_keys.h" @@ -75,101 +75,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "inline_bots/inline_results_widget.h" #include "chat_helpers/emoji_suggestions_widget.h" -// Smart pointer for QObject*, has move semantics, destroys object if it doesn't have a parent. -template -class test_ptr { -public: - test_ptr(std::nullptr_t) { - } - - // No default constructor, but constructors with at least - // one argument are simply make functions. - template - explicit test_ptr(Parent &&parent, Args&&... args) : _object(new Object(std::forward(parent), std::forward(args)...)) { - } - - test_ptr(const test_ptr &other) = delete; - test_ptr &operator=(const test_ptr &other) = delete; - test_ptr(test_ptr &&other) : _object(base::take(other._object)) { - } - test_ptr &operator=(test_ptr &&other) { - auto temp = std::move(other); - destroy(); - std::swap(_object, temp._object); - return *this; - } - - template ::value>> - test_ptr(test_ptr &&other) : _object(base::take(other._object)) { - } - - template ::value>> - test_ptr &operator=(test_ptr &&other) { - _object = base::take(other._object); - return *this; - } - - test_ptr &operator=(std::nullptr_t) { - _object = nullptr; - return *this; - } - - // So we can pass this pointer to methods like connect(). - Object *data() const { - return static_cast(_object); - } - operator Object*() const { - return data(); - } - - explicit operator bool() const { - return _object != nullptr; - } - - Object *operator->() const { - return data(); - } - Object &operator*() const { - return *data(); - } - - // Use that instead "= new Object(parent, ...)" - template - void create(Parent &&parent, Args&&... args) { - destroy(); - _object = new Object(std::forward(parent), std::forward(args)...); - } - void destroy() { - delete base::take(_object); - } - void destroyDelayed() { - if (_object) { - if (auto widget = base::up_cast(data())) { - widget->hide(); - } - base::take(_object)->deleteLater(); - } - } - - ~test_ptr() { - if (auto pointer = _object) { - if (!pointer->parent()) { - destroy(); - } - } - } - -private: - template - friend class test_ptr; - - QPointer _object; - -}; - -class TestClass; -test_ptr tmp = { nullptr }; - namespace { constexpr auto kSaveTabbedSelectorSectionTimeoutMs = 1000; @@ -739,7 +644,9 @@ HistoryWidget::HistoryWidget(QWidget *parent, not_null cont _botCommandStart->hide(); _tabbedSelectorToggle->installEventFilter(_tabbedPanel); - _tabbedSelectorToggle->setClickedCallback([this] { toggleTabbedSelectorMode(); }); + _tabbedSelectorToggle->setClickedCallback([this] { + toggleTabbedSelectorMode(); + }); connect(_botKeyboardShow, SIGNAL(clicked()), this, SLOT(onKbToggle())); connect(_botKeyboardHide, SIGNAL(clicked()), this, SLOT(onKbToggle())); @@ -819,22 +726,6 @@ HistoryWidget::HistoryWidget(QWidget *parent, not_null cont } } })); - subscribe(controller->window()->widgetGrabbed(), [this] { - // Qt bug workaround: QWidget::render() for an arbitrary widget calls - // sendPendingMoveAndResizeEvents(true, true) for the whole window, - // which does something like: - // - // setAttribute(Qt::WA_UpdatesDisabled); - // sendEvent(QResizeEvent); - // setAttribute(Qt::WA_UpdatesDisabled, false); - // - // So if we create TabbedSection widget in HistoryWidget::resizeEvent() - // it will get an enabled Qt::WA_UpdatesDisabled from its parent and it - // will never be rendered, because no one will ever remove that attribute. - // - // So we force HistoryWidget::resizeEvent() here, without WA_UpdatesDisabled. - myEnsureResized(this); - }); subscribe(Auth().data().pendingHistoryResize(), [this] { handlePendingHistoryUpdate(); }); subscribe(Auth().data().queryItemVisibility(), [this](const AuthSessionData::ItemVisibilityQuery &query) { if (_a_show.animating() || _history != query.item->history() || query.item->detached() || !isVisible()) { @@ -1152,9 +1043,6 @@ void HistoryWidget::orderWidgets() { _reportSpamPanel->raise(); } _topShadow->raise(); - if (_rightShadow) { - _rightShadow->raise(); - } if (_membersDropdown) { _membersDropdown->raise(); } @@ -1383,14 +1271,6 @@ void HistoryWidget::updateRecentStickers() { _tabbedSelector->refreshStickers(); } -void HistoryWidget::stickersInstalled(uint64 setId) { - if (_tabbedPanel) { - _tabbedPanel->stickersInstalled(setId); - } else if (_tabbedSection) { - _tabbedSection->stickersInstalled(setId); - } -} - void HistoryWidget::sendActionDone(const MTPBool &result, mtpRequestId req) { for (auto i = _sendActionRequests.begin(), e = _sendActionRequests.end(); i != e; ++i) { if (i.value() == req) { @@ -2108,20 +1988,10 @@ void HistoryWidget::updateControlsVisibility() { updateHistoryDownVisibility(); updateUnreadMentionsVisibility(); if (!_history || _a_show.animating()) { - if (_tabbedSection && !_tabbedSection->isHidden()) { - _tabbedSection->beforeHiding(); - } hideChildren(); return; } - if (_tabbedSection) { - if (_tabbedSection->isHidden()) { - _tabbedSection->show(); - _tabbedSection->afterShown(); - } - _rightShadow->show(); - } if (_pinnedBar) { _pinnedBar->cancel->show(); _pinnedBar->shadow->show(); @@ -2287,7 +2157,7 @@ void HistoryWidget::updateControlsVisibility() { update(); } } - checkTabbedSelectorToggleTooltip(); + //checkTabbedSelectorToggleTooltip(); updateMouseTracking(); } @@ -2807,7 +2677,16 @@ void HistoryWidget::saveEditMsg() { if (!sentEntities.v.isEmpty()) { sendFlags |= MTPmessages_EditMessage::Flag::f_entities; } - _saveEditMsgRequestId = MTP::send(MTPmessages_EditMessage(MTP_flags(sendFlags), _history->peer->input, MTP_int(_editMsgId), MTP_string(sending.text), MTPnullMarkup, sentEntities), rpcDone(&HistoryWidget::saveEditMsgDone, _history), rpcFail(&HistoryWidget::saveEditMsgFail, _history)); + _saveEditMsgRequestId = MTP::send( + MTPmessages_EditMessage( + MTP_flags(sendFlags), + _history->peer->input, + MTP_int(_editMsgId), + MTP_string(sending.text), + MTPnullMarkup, + sentEntities), + rpcDone(&HistoryWidget::saveEditMsgDone, _history), + rpcFail(&HistoryWidget::saveEditMsgFail, _history)); } void HistoryWidget::saveEditMsgDone(History *history, const MTPUpdates &updates, mtpRequestId req) { @@ -3077,15 +2956,8 @@ void HistoryWidget::showAnimated(Window::SlideDirection direction, const Window: _topShadow->setVisible(params.withTopBarShadow ? false : true); _cacheOver = App::main()->grabForShowAnimation(params); - if (_tabbedSection && !_tabbedSection->isHidden()) { - _tabbedSection->beforeHiding(); - } hideChildren(); if (params.withTopBarShadow) _topShadow->show(); - if (params.withTabbedSection && _tabbedSection) { - _tabbedSection->show(); - _tabbedSection->afterShown(); - } if (_showDirection == Window::SlideDirection::FromLeft) { std::swap(_cacheUnder, _cacheOver); @@ -3507,19 +3379,11 @@ bool HistoryWidget::eventFilter(QObject *obj, QEvent *e) { return TWidget::eventFilter(obj, e); } -bool HistoryWidget::wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn, Window::Column playerColumn) { - if (playerColumn == Window::Column::Third && _tabbedSection) { - auto tabbedColumn = (myColumn == Window::Column::First) ? Window::Column::Second : Window::Column::Third; - return _tabbedSection->wheelEventFromFloatPlayer(e, tabbedColumn, playerColumn); - } +bool HistoryWidget::wheelEventFromFloatPlayer(QEvent *e) { return _scroll->viewportEvent(e); } -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); - } +QRect HistoryWidget::rectForFloatPlayer() const { return mapToGlobal(_scroll->geometry()); } @@ -3827,7 +3691,7 @@ bool HistoryWidget::paintTopBar(Painter &p, int decreaseWidth, TimeMs ms) { auto nameleft = st::topBarArrowPadding.right() + increaseLeft; auto nametop = st::topBarArrowPadding.top(); auto statustop = st::topBarHeight - st::topBarArrowPadding.bottom() - st::dialogsTextFont->height; - auto namewidth = _chatWidth - decreaseWidth - nameleft - st::topBarArrowPadding.right(); + auto namewidth = width() - decreaseWidth - nameleft - st::topBarArrowPadding.right(); p.setFont(st::dialogsTextFont); if (!_history->paintSendAction(p, nameleft, statustop, namewidth, width(), st::historyStatusFgTyping, ms)) { p.setPen(_titlePeerTextOnline ? st::historyStatusFgActive : st::historyStatusFg); @@ -3888,113 +3752,66 @@ void HistoryWidget::onModerateKeyActivate(int index, bool *outHandled) { void HistoryWidget::topBarClick() { if (Adaptive::OneColumn() || !App::main()->stackIsEmpty()) { App::main()->showBackFromStack(); - } else { - if (_history) Ui::showPeerProfile(_peer); + } else if (_peer) { + controller()->showPeerInfo(_peer); } } -void HistoryWidget::updateTabbedSelectorSectionShown() { - auto tabbedSelectorSectionEnabled = Auth().data().tabbedSelectorSectionEnabled(); - auto useTabbedSection = tabbedSelectorSectionEnabled && (width() >= minimalWidthForTabbedSelectorSection()); - if (_tabbedSectionUsed == useTabbedSection) { +void HistoryWidget::pushTabbedSelectorToThirdSection() { + if (!_history || !_tabbedPanel) { return; } - _tabbedSectionUsed = useTabbedSection; + _tabbedSelectorToggle->setColorOverrides( + &st::historyAttachEmojiActive, + &st::historyRecordVoiceFgActive, + &st::historyRecordVoiceRippleBgActive); + auto destroyingPanel = std::move(_tabbedPanel); + controller()->resizeForThirdSection(); + controller()->showSection(ChatHelpers::TabbedMemento( + destroyingPanel->takeSelector(), + base::lambda_guarded(this, [this]( + object_ptr selector) { + returnTabbedSelector(std::move(selector)); + }))); +} - // Use a separate bool flag instead of just (_tabbedSection != nullptr), because - // _tabbedPanel->takeSelector() calls QWidget::render(), which calls - // sendPendingMoveAndResizeEvents() for all widgets in the window, which can lead - // to a new HistoryWidget::resizeEvent() call and an infinite recursion here. - if (_tabbedSectionUsed) { - _tabbedSection.create(this, controller(), _tabbedPanel->takeSelector()); - _tabbedSection->setCancelledCallback([this] { setInnerFocus(); }); - _tabbedSelectorToggle->setColorOverrides(&st::historyAttachEmojiActive, &st::historyRecordVoiceFgActive, &st::historyRecordVoiceRippleBgActive); - _rightShadow.create(this, st::shadowFg); - auto destroyingPanel = std::move(_tabbedPanel); - updateControlsVisibility(); - } else { - _tabbedPanel.create(this, controller(), _tabbedSection->takeSelector()); - _tabbedPanel->hide(); - _tabbedSelectorToggle->installEventFilter(_tabbedPanel); - _tabbedSection.destroy(); - _tabbedSelectorToggle->setColorOverrides(nullptr, nullptr, nullptr); - _rightShadow.destroy(); - _tabbedSelectorToggleTooltipShown = false; +void HistoryWidget::pushInfoToThirdSection() { + if (!_peer) { + return; } - checkTabbedSelectorToggleTooltip(); - orderWidgets(); -} - -void HistoryWidget::checkTabbedSelectorToggleTooltip() { - if (_tabbedSection && !_tabbedSection->isHidden() && !_tabbedSelectorToggle->isHidden()) { - if (!_tabbedSelectorToggleTooltipShown) { - auto shownCount = Auth().data().tabbedSelectorSectionTooltipShown(); - if (shownCount < kTabbedSelectorToggleTooltipCount) { - _tabbedSelectorToggleTooltipShown = true; - _tabbedSelectorToggleTooltip.create(this, object_ptr(this, lang(lng_emoji_hide_panel), Ui::FlatLabel::InitType::Simple, st::defaultImportantTooltipLabel), st::defaultImportantTooltip); - _tabbedSelectorToggleTooltip->setHiddenCallback([this] { - _tabbedSelectorToggleTooltip.destroy(); - }); - InvokeQueued(_tabbedSelectorToggleTooltip, [this, shownCount] { - Auth().data().setTabbedSelectorSectionTooltipShown(shownCount + 1); - Auth().saveDataDelayed(kTabbedSelectorToggleTooltipTimeoutMs); - - updateTabbedSelectorToggleTooltipGeometry(); - _tabbedSelectorToggleTooltip->hideAfter(kTabbedSelectorToggleTooltipTimeoutMs); - _tabbedSelectorToggleTooltip->toggleAnimated(true); - }); - } - } - } else { - _tabbedSelectorToggleTooltip.destroy(); - } -} - -int HistoryWidget::tabbedSelectorSectionWidth() const { - return st::emojiPanWidth; -} - -int HistoryWidget::minimalWidthForTabbedSelectorSection() const { - return st::windowMinWidth + tabbedSelectorSectionWidth(); -} - -bool HistoryWidget::willSwitchToTabbedSelectorWithWidth(int newWidth) const { - if (!Auth().data().tabbedSelectorSectionEnabled()) { - return false; - } else if (_tabbedSectionUsed) { - return false; - } - return (newWidth >= minimalWidthForTabbedSelectorSection()); + controller()->showPeerInfo(_peer); } void HistoryWidget::toggleTabbedSelectorMode() { - if (_tabbedSection) { - Auth().data().setTabbedSelectorSectionEnabled(false); - Auth().saveDataDelayed(kSaveTabbedSelectorSectionTimeoutMs); - updateTabbedSelectorSectionShown(); - recountChatWidth(); - updateControlsGeometry(); - } else if (controller()->canProvideChatWidth(minimalWidthForTabbedSelectorSection())) { - if (!Auth().data().tabbedSelectorSectionEnabled()) { + if (_tabbedPanel) { + if (controller()->canShowThirdSection()) { Auth().data().setTabbedSelectorSectionEnabled(true); Auth().saveDataDelayed(kSaveTabbedSelectorSectionTimeoutMs); + pushTabbedSelectorToThirdSection(); + } else { + _tabbedPanel->toggleAnimated(); } - controller()->provideChatWidth(minimalWidthForTabbedSelectorSection()); - updateTabbedSelectorSectionShown(); - recountChatWidth(); - updateControlsGeometry(); } else { - Assert(_tabbedPanel != nullptr); - _tabbedPanel->toggleAnimated(); + controller()->closeThirdSection(); } } +void HistoryWidget::returnTabbedSelector( + object_ptr selector) { + _tabbedPanel.create( + this, + controller(), + std::move(selector)); + _tabbedPanel->hide(); + _tabbedSelectorToggle->installEventFilter(_tabbedPanel); + _tabbedSelectorToggle->setColorOverrides(nullptr, nullptr, nullptr); + _tabbedSelectorToggleTooltipShown = false; +} + void HistoryWidget::recountChatWidth() { - _chatWidth = width(); - if (_tabbedSection) { - _chatWidth -= _tabbedSection->width(); - } - auto layout = (_chatWidth < st::adaptiveChatWideWidth) ? Adaptive::ChatLayout::Normal : Adaptive::ChatLayout::Wide; + auto layout = (width() < st::adaptiveChatWideWidth) + ? Adaptive::ChatLayout::Normal + : Adaptive::ChatLayout::Wide; if (layout != Global::AdaptiveChatLayout()) { Global::SetAdaptiveChatLayout(layout); Adaptive::Changed().notify(true); @@ -4106,11 +3923,11 @@ void HistoryWidget::moveFieldControls() { auto keyboardHeight = 0; auto bottom = height(); auto maxKeyboardHeight = st::historyComposeFieldMaxHeight - _field->height(); - _keyboard->resizeToWidth(_chatWidth, maxKeyboardHeight); + _keyboard->resizeToWidth(width(), maxKeyboardHeight); if (_kbShown) { keyboardHeight = qMin(_keyboard->height(), maxKeyboardHeight); bottom -= keyboardHeight; - _kbScroll->setGeometryToLeft(0, bottom, _chatWidth, keyboardHeight); + _kbScroll->setGeometryToLeft(0, bottom, width(), keyboardHeight); } // _attachToggle --------- _inlineResults -------------------------------------- _tabbedPanel --------- _fieldBarCancel @@ -4121,7 +3938,7 @@ void HistoryWidget::moveFieldControls() { auto left = 0; _attachToggle->moveToLeft(left, buttonsBottom); left += _attachToggle->width(); _field->moveToLeft(left, bottom - _field->height() - st::historySendPadding); - auto right = (width() - _chatWidth) + st::historySendRight; + auto right = st::historySendRight; _send->moveToRight(right, buttonsBottom); right += _send->width(); _tabbedSelectorToggle->moveToRight(right, buttonsBottom); updateTabbedSelectorToggleTooltipGeometry(); @@ -4130,7 +3947,7 @@ void HistoryWidget::moveFieldControls() { _botCommandStart->moveToRight(right, buttonsBottom); _silent->moveToRight(right, buttonsBottom); - _fieldBarCancel->moveToRight(width() - _chatWidth, _field->y() - st::historySendPadding - _fieldBarCancel->height()); + _fieldBarCancel->moveToRight(0, _field->y() - st::historySendPadding - _fieldBarCancel->height()); if (_inlineResults) { _inlineResults->moveBottom(_field->y() - st::historySendPadding); } @@ -4138,7 +3955,11 @@ void HistoryWidget::moveFieldControls() { _tabbedPanel->moveBottom(buttonsBottom); } - auto fullWidthButtonRect = myrtlrect(0, bottom - _botStart->height(), _chatWidth, _botStart->height()); + auto fullWidthButtonRect = myrtlrect( + 0, + bottom - _botStart->height(), + width(), + _botStart->height()); _botStart->setGeometry(fullWidthButtonRect); _unblock->setGeometry(fullWidthButtonRect); _joinChannel->setGeometry(fullWidthButtonRect); @@ -4156,7 +3977,7 @@ void HistoryWidget::updateTabbedSelectorToggleTooltipGeometry() { void HistoryWidget::updateFieldSize() { auto kbShowShown = _history && !_kbShown && _keyboard->hasMarkup(); - auto fieldWidth = _chatWidth - _attachToggle->width() - st::historySendRight; + auto fieldWidth = width() - _attachToggle->width() - st::historySendRight; fieldWidth -= _send->width(); fieldWidth -= _tabbedSelectorToggle->width(); if (kbShowShown) fieldWidth -= _botKeyboardShow->width(); @@ -4780,31 +4601,28 @@ void HistoryWidget::handlePendingHistoryUpdate() { } void HistoryWidget::resizeEvent(QResizeEvent *e) { - updateTabbedSelectorSectionShown(); + //updateTabbedSelectorSectionShown(); recountChatWidth(); updateControlsGeometry(); } void HistoryWidget::updateControlsGeometry() { - if (_tabbedSection) { - _tabbedSection->setGeometryToRight(0, 0, st::emojiPanWidth, height()); - } - _topBar->setGeometryToLeft(0, 0, _chatWidth, st::topBarHeight); + _topBar->setGeometryToLeft(0, 0, width(), st::topBarHeight); moveFieldControls(); auto scrollAreaTop = _topBar->bottomNoMargins(); if (_pinnedBar) { - _pinnedBar->cancel->moveToLeft(_chatWidth - _pinnedBar->cancel->width(), scrollAreaTop); + _pinnedBar->cancel->moveToLeft(width() - _pinnedBar->cancel->width(), scrollAreaTop); scrollAreaTop += st::historyReplyHeight; - _pinnedBar->shadow->setGeometryToLeft(0, scrollAreaTop, _chatWidth, st::lineWidth); + _pinnedBar->shadow->setGeometryToLeft(0, scrollAreaTop, width(), st::lineWidth); } if (_scroll->y() != scrollAreaTop) { _scroll->moveToLeft(0, scrollAreaTop); _fieldAutocomplete->setBoundings(_scroll->geometry()); } if (_reportSpamPanel) { - _reportSpamPanel->setGeometryToLeft(0, _scroll->y(), _chatWidth, _reportSpamPanel->height()); + _reportSpamPanel->setGeometryToLeft(0, _scroll->y(), width(), _reportSpamPanel->height()); } updateHistoryGeometry(false, false, { ScrollChangeAdd, App::main() ? App::main()->contentScrollAddToY() : 0 }); @@ -4834,12 +4652,13 @@ void HistoryWidget::updateControlsGeometry() { break; } - if (_rightShadow) { - _rightShadow->setGeometryToLeft(_chatWidth - st::lineWidth, 0, st::lineWidth, height()); - } auto topShadowLeft = (Adaptive::OneColumn() || _inGrab) ? 0 : st::lineWidth; - auto topShadowRight = _rightShadow ? st::lineWidth : 0; - _topShadow->setGeometryToLeft(topShadowLeft, _topBar->bottomNoMargins(), _chatWidth - topShadowLeft - topShadowRight, st::lineWidth); + auto topShadowRight = (Adaptive::ThreeColumn() && !_inGrab && _peer) ? st::lineWidth : 0; + _topShadow->setGeometryToLeft( + topShadowLeft, + _topBar->bottomNoMargins(), + width() - topShadowLeft - topShadowRight, + st::lineWidth); } void HistoryWidget::itemRemoved(HistoryItem *item) { @@ -4963,9 +4782,9 @@ void HistoryWidget::updateHistoryGeometry(bool initial, bool loadedDown, const S auto wasScrollTop = _scroll->scrollTop(); auto wasScrollTopMax = _scroll->scrollTopMax(); auto wasAtBottom = wasScrollTop + 1 > wasScrollTopMax; - auto needResize = (_scroll->width() != _chatWidth) || (_scroll->height() != newScrollHeight); + auto needResize = (_scroll->width() != width()) || (_scroll->height() != newScrollHeight); if (needResize) { - _scroll->resize(_chatWidth, newScrollHeight); + _scroll->resize(width(), newScrollHeight); // on initial updateListSize we didn't put the _scroll->scrollTop correctly yet // so visibleAreaUpdated() call will erase it with the new (undefined) value if (!initial) { @@ -6379,7 +6198,7 @@ void HistoryWidget::updateReplyToName() { void HistoryWidget::updateField() { auto fieldAreaTop = _scroll->y() + _scroll->height(); - rtlupdate(0, fieldAreaTop, _chatWidth, height() - fieldAreaTop); + rtlupdate(0, fieldAreaTop, width(), height() - fieldAreaTop); } void HistoryWidget::drawField(Painter &p, const QRect &rect) { @@ -6402,7 +6221,7 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) { backh += st::historyReplyHeight; } auto drawWebPagePreview = (_previewData && _previewData->pendingTill >= 0) && !_replyForwardPressed; - p.fillRect(myrtlrect(0, backy, _chatWidth, backh), st::historyReplyBg); + p.fillRect(myrtlrect(0, backy, width(), backh), st::historyReplyBg); if (_editMsgId || _replyToId || (!hasForward && _kbReplyTo)) { auto replyLeft = st::historyReplySkip; (_editMsgId ? st::historyEditIcon : st::historyReplyIcon).paint(p, st::historyReplyIconPosition + QPoint(0, backy), width()); @@ -6420,14 +6239,14 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) { if (_editMsgId) { paintEditHeader(p, rect, replyLeft, backy); } else { - _replyToName.drawElided(p, replyLeft, backy + st::msgReplyPadding.top(), _chatWidth - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right()); + _replyToName.drawElided(p, replyLeft, backy + st::msgReplyPadding.top(), width() - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right()); } p.setPen(((drawMsgText->toHistoryMessage() && drawMsgText->toHistoryMessage()->emptyText()) || drawMsgText->serviceMsg()) ? st::historyComposeAreaFgService : st::historyComposeAreaFg); - _replyEditMsgText.drawElided(p, replyLeft, backy + st::msgReplyPadding.top() + st::msgServiceNameFont->height, _chatWidth - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right()); + _replyEditMsgText.drawElided(p, replyLeft, backy + st::msgReplyPadding.top() + st::msgServiceNameFont->height, width() - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right()); } else { p.setFont(st::msgDateFont); p.setPen(st::historyComposeAreaFgService); - p.drawText(replyLeft, backy + st::msgReplyPadding.top() + (st::msgReplyBarSize.height() - st::msgDateFont->height) / 2 + st::msgDateFont->ascent, st::msgDateFont->elided(lang(lng_profile_loading), _chatWidth - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right())); + p.drawText(replyLeft, backy + st::msgReplyPadding.top() + (st::msgReplyBarSize.height() - st::msgDateFont->height) / 2 + st::msgDateFont->ascent, st::msgDateFont->elided(lang(lng_profile_loading), width() - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right())); } } } else if (hasForward) { @@ -6451,7 +6270,7 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) { p.setPen(st::historyReplyNameFg); _toForwardFrom.drawElided(p, forwardLeft, backy + st::msgReplyPadding.top(), width() - forwardLeft - _fieldBarCancel->width() - st::msgReplyPadding.right()); p.setPen(serviceColor ? st::historyComposeAreaFgService : st::historyComposeAreaFg); - _toForwardText.drawElided(p, forwardLeft, backy + st::msgReplyPadding.top() + st::msgServiceNameFont->height, _chatWidth - forwardLeft - _fieldBarCancel->width() - st::msgReplyPadding.right()); + _toForwardText.drawElided(p, forwardLeft, backy + st::msgReplyPadding.top() + st::msgServiceNameFont->height, width() - forwardLeft - _fieldBarCancel->width() - st::msgReplyPadding.right()); } } if (drawWebPagePreview) { @@ -6471,14 +6290,14 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) { previewLeft += st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x(); } p.setPen(st::historyReplyNameFg); - _previewTitle.drawElided(p, previewLeft, backy + st::msgReplyPadding.top(), _chatWidth - previewLeft - _fieldBarCancel->width() - st::msgReplyPadding.right()); + _previewTitle.drawElided(p, previewLeft, backy + st::msgReplyPadding.top(), width() - previewLeft - _fieldBarCancel->width() - st::msgReplyPadding.right()); p.setPen(st::historyComposeAreaFg); - _previewDescription.drawElided(p, previewLeft, backy + st::msgReplyPadding.top() + st::msgServiceNameFont->height, _chatWidth - previewLeft - _fieldBarCancel->width() - st::msgReplyPadding.right()); + _previewDescription.drawElided(p, previewLeft, backy + st::msgReplyPadding.top() + st::msgServiceNameFont->height, width() - previewLeft - _fieldBarCancel->width() - st::msgReplyPadding.right()); } } void HistoryWidget::drawRestrictedWrite(Painter &p) { - auto rect = myrtlrect(0, height() - _unblock->height(), _chatWidth, _unblock->height()); + auto rect = myrtlrect(0, height() - _unblock->height(), width(), _unblock->height()); p.fillRect(rect, st::historyReplyBg); p.setFont(st::normalFont); @@ -6487,7 +6306,7 @@ void HistoryWidget::drawRestrictedWrite(Painter &p) { } void HistoryWidget::paintEditHeader(Painter &p, const QRect &rect, int left, int top) const { - if (!rect.intersects(myrtlrect(left, top, _chatWidth - left, st::normalFont->height))) { + if (!rect.intersects(myrtlrect(left, top, width() - left, st::normalFont->height))) { return; } @@ -6517,7 +6336,7 @@ void HistoryWidget::paintEditHeader(Painter &p, const QRect &rect, int left, int } // Restart timer only if we are sure that we've painted the whole timer. - if (rect.contains(myrtlrect(left, top, _chatWidth - left, st::normalFont->height)) && updateIn > 0) { + if (rect.contains(myrtlrect(left, top, width() - left, st::normalFont->height)) && updateIn > 0) { _updateEditTimeLeftDisplay.start(updateIn); } @@ -6546,7 +6365,7 @@ void HistoryWidget::drawRecording(Painter &p, float64 recordActive) { p.drawText(_attachToggle->x() + _tabbedSelectorToggle->width(), _attachToggle->y() + st::historyRecordTextTop + st::historyRecordFont->ascent, duration); int32 left = _attachToggle->x() + _tabbedSelectorToggle->width() + st::historyRecordFont->width(duration) + ((_send->width() - st::historyRecordVoice.width()) / 2); - int32 right = _chatWidth - _send->width(); + int32 right = width() - _send->width(); p.setPen(anim::pen(st::historyRecordCancel, st::historyRecordCancelActive, 1. - recordActive)); p.drawText(left + (right - left - _recordCancelWidth) / 2, _attachToggle->y() + st::historyRecordTextTop + st::historyRecordFont->ascent, lang(lng_record_cancel)); @@ -6559,7 +6378,7 @@ void HistoryWidget::drawPinnedBar(Painter &p) { Text *from = 0, *text = 0; bool serviceColor = false, hasForward = readyToForward(); ImagePtr preview; - p.fillRect(myrtlrect(0, top, _chatWidth, st::historyReplyHeight), st::historyPinnedBg); + p.fillRect(myrtlrect(0, top, width(), st::historyReplyHeight), st::historyPinnedBg); top += st::msgReplyPadding.top(); QRect rbar(myrtlrect(st::msgReplyBarSkip + st::msgReplyBarPos.x(), top + st::msgReplyBarPos.y(), st::msgReplyBarSize.width(), st::msgReplyBarSize.height())); @@ -6580,11 +6399,11 @@ void HistoryWidget::drawPinnedBar(Painter &p) { p.drawText(left, top + st::msgServiceNameFont->ascent, lang(lng_pinned_message)); p.setPen(((_pinnedBar->msg->toHistoryMessage() && _pinnedBar->msg->toHistoryMessage()->emptyText()) || _pinnedBar->msg->serviceMsg()) ? st::historyComposeAreaFgService : st::historyComposeAreaFg); - _pinnedBar->text.drawElided(p, left, top + st::msgServiceNameFont->height, _chatWidth - left - _pinnedBar->cancel->width() - st::msgReplyPadding.right()); + _pinnedBar->text.drawElided(p, left, top + st::msgServiceNameFont->height, width() - left - _pinnedBar->cancel->width() - st::msgReplyPadding.right()); } else { p.setFont(st::msgDateFont); p.setPen(st::historyComposeAreaFgService); - p.drawText(left, top + (st::msgReplyBarSize.height() - st::msgDateFont->height) / 2 + st::msgDateFont->ascent, st::msgDateFont->elided(lang(lng_profile_loading), _chatWidth - left - _pinnedBar->cancel->width() - st::msgReplyPadding.right())); + p.drawText(left, top + (st::msgReplyBarSize.height() - st::msgDateFont->height) / 2 + st::msgDateFont->ascent, st::msgDateFont->elided(lang(lng_profile_loading), width() - left - _pinnedBar->cancel->width() - st::msgReplyPadding.right())); } } @@ -6607,7 +6426,7 @@ void HistoryWidget::paintEvent(QPaintEvent *e) { _unreadMentionsShown.step(ms); auto progress = _a_show.current(ms, 1.); if (_a_show.animating()) { - auto animationWidth = (!_tabbedSection || _tabbedSection->isHidden()) ? width() : _chatWidth; + auto animationWidth = width(); auto retina = cIntRetinaFactor(); auto fromLeft = (_showDirection == Window::SlideDirection::FromLeft); auto coordUnder = fromLeft ? anim::interpolate(-st::slideShift, 0, progress) : anim::interpolate(0, -st::slideShift, progress); @@ -6625,7 +6444,7 @@ void HistoryWidget::paintEvent(QPaintEvent *e) { return; } - QRect fill(0, 0, _history ? _chatWidth : width(), App::main()->height()); + QRect fill(0, 0, width(), App::main()->height()); auto fromy = App::main()->backgroundFromY(); auto x = 0, y = 0; QPixmap cached = App::main()->cachedBackground(fill, x, y); diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index 390ea1ee8..514ec2c38 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -207,15 +207,13 @@ public: void unreadCountChanged(History *history); QRect historyRect() const; - int tabbedSelectorSectionWidth() const; - int minimalWidthForTabbedSelectorSection() const; - bool willSwitchToTabbedSelectorWithWidth(int newWidth) const; + void pushTabbedSelectorToThirdSection(); + void pushInfoToThirdSection(); void updateSendAction(History *history, SendAction::Type type, int32 progress = 0); void cancelSendAction(History *history, SendAction::Type type); void updateRecentStickers(); - void stickersInstalled(uint64 setId); void sendActionDone(const MTPBool &result, mtpRequestId req); void destroyData(); @@ -347,8 +345,8 @@ public: void deleteSelectedItems(bool forEveryone); // Float player interface. - bool wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn, Window::Column playerColumn) override; - QRect rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const override; + bool wheelEventFromFloatPlayer(QEvent *e) override; + QRect rectForFloatPlayer() const override; void app_sendBotCallback(const HistoryMessageReplyMarkup::Button *button, not_null msg, int row, int col); @@ -479,12 +477,14 @@ private: QStringList filesToSend; bool allFilesForCompress = true; }; + using TabbedPanel = ChatHelpers::TabbedPanel; + using TabbedSelector = ChatHelpers::TabbedSelector; void handlePendingHistoryUpdate(); void fullPeerUpdated(PeerData *peer); void topBarClick(); void toggleTabbedSelectorMode(); - void updateTabbedSelectorSectionShown(); + void returnTabbedSelector(object_ptr selector); void recountChatWidth(); void setReportSpamStatus(DBIPeerReportSpamStatus status); void historyDownClicked(); @@ -562,7 +562,6 @@ private: int _toForwardNameVersion = 0; int _forwardingItemRemovedSubscription = 0; - int _chatWidth = 0; MsgId _editMsgId = 0; HistoryItem *_replyEditMsg = nullptr; @@ -822,10 +821,8 @@ private: QTimer _membersDropdownShowTimer; object_ptr _inlineResults = { nullptr }; - object_ptr _tabbedPanel; - object_ptr _tabbedSection = { nullptr }; - QPointer _tabbedSelector; - bool _tabbedSectionUsed = false; + object_ptr _tabbedPanel; + QPointer _tabbedSelector; DragState _attachDrag = DragStateNone; object_ptr _attachDragDocument, _attachDragPhoto; @@ -863,7 +860,6 @@ private: QTimer _saveDraftTimer, _saveCloudDraftTimer; object_ptr _topShadow; - object_ptr _rightShadow = { nullptr }; bool _inGrab = false; }; diff --git a/Telegram/SourceFiles/info/info_layer_wrap.cpp b/Telegram/SourceFiles/info/info_layer_wrap.cpp index e51fcdc28..24fb408d1 100644 --- a/Telegram/SourceFiles/info/info_layer_wrap.cpp +++ b/Telegram/SourceFiles/info/info_layer_wrap.cpp @@ -106,7 +106,7 @@ void LayerWrap::parentResized() { hide(); setParent(nullptr); auto localCopy = _controller; - localCopy->showWideSection( + localCopy->showSection( MoveMemento(std::move(_content), Wrap::Narrow)); localCopy->hideSpecialLayer(LayerOption::ForceFast); } else { diff --git a/Telegram/SourceFiles/info/info_media_inner_widget.cpp b/Telegram/SourceFiles/info/info_media_inner_widget.cpp index 068e3356e..edee58310 100644 --- a/Telegram/SourceFiles/info/info_media_inner_widget.cpp +++ b/Telegram/SourceFiles/info/info_media_inner_widget.cpp @@ -30,14 +30,6 @@ InnerWidget::InnerWidget( : RpWidget(parent) , _peer(peer) , _type(type) { - base::lambda launch = [this, &launch](int counter) { - QTimer::singleShot(500, this, [this, launch, counter] { - _rowsHeightFake += 300; - resizeToWidth(width(), _minHeight); - launch(counter - 1); - }); - }; - launch(10); } void InnerWidget::visibleTopBottomUpdated( diff --git a/Telegram/SourceFiles/info/info_memento.cpp b/Telegram/SourceFiles/info/info_memento.cpp index 967e85d77..8c12d74ef 100644 --- a/Telegram/SourceFiles/info/info_memento.cpp +++ b/Telegram/SourceFiles/info/info_memento.cpp @@ -165,7 +165,14 @@ std::unique_ptr Memento::Default( object_ptr Memento::createWidget( QWidget *parent, not_null controller, + Window::Column column, const QRect &geometry) { + if (column == Window::Column::Third) { + return object_ptr( + parent, + controller, + this); + } return object_ptr( parent, controller, @@ -193,21 +200,24 @@ MoveMemento::MoveMemento( object_ptr MoveMemento::createWidget( QWidget *parent, not_null controller, + Window::Column column, const QRect &geometry) { - if (_wrap == Wrap::Narrow) { + if (_wrap == Wrap::Narrow && column != Window::Column::Third) { auto result = object_ptr( parent, controller, this); result->setGeometry(geometry); return result; + } else if (_wrap == Wrap::Side && column == Window::Column::Third) { + auto result = object_ptr( + parent, + controller, + this); + result->setGeometry(geometry); + return result; } - auto result = object_ptr( - parent, - controller, - this); - result->setGeometry(geometry); - return result; + return nullptr; } object_ptr MoveMemento::createLayer( diff --git a/Telegram/SourceFiles/info/info_memento.h b/Telegram/SourceFiles/info/info_memento.h index 2d2321e31..2c0959b0a 100644 --- a/Telegram/SourceFiles/info/info_memento.h +++ b/Telegram/SourceFiles/info/info_memento.h @@ -195,6 +195,7 @@ public: object_ptr createWidget( QWidget *parent, not_null controller, + Window::Column column, const QRect &geometry) override; object_ptr createLayer( @@ -232,6 +233,7 @@ public: object_ptr createWidget( QWidget *parent, not_null controller, + Window::Column column, const QRect &geometry) override; object_ptr createLayer( diff --git a/Telegram/SourceFiles/info/info_narrow_wrap.cpp b/Telegram/SourceFiles/info/info_narrow_wrap.cpp index 665aea193..cf60e9c5f 100644 --- a/Telegram/SourceFiles/info/info_narrow_wrap.cpp +++ b/Telegram/SourceFiles/info/info_narrow_wrap.cpp @@ -176,20 +176,20 @@ void NarrowWrap::resizeEvent(QResizeEvent *e) { } void NarrowWrap::paintEvent(QPaintEvent *e) { + SectionWidget::paintEvent(e); + if (animating()) { + return; + } + Painter p(this); p.fillRect(e->rect(), st::profileBg); } -bool NarrowWrap::wheelEventFromFloatPlayer( - QEvent *e, - Window::Column myColumn, - Window::Column playerColumn) { +bool NarrowWrap::wheelEventFromFloatPlayer(QEvent *e) { return _content->wheelEventFromFloatPlayer(e); } -QRect NarrowWrap::rectForFloatPlayer( - Window::Column myColumn, - Window::Column playerColumn) const { +QRect NarrowWrap::rectForFloatPlayer() const { return _content->rectForFloatPlayer(); } diff --git a/Telegram/SourceFiles/info/info_narrow_wrap.h b/Telegram/SourceFiles/info/info_narrow_wrap.h index 2493c3711..b94090573 100644 --- a/Telegram/SourceFiles/info/info_narrow_wrap.h +++ b/Telegram/SourceFiles/info/info_narrow_wrap.h @@ -79,13 +79,8 @@ public: not_null memento); // Float player interface. - bool wheelEventFromFloatPlayer( - QEvent *e, - Window::Column myColumn, - Window::Column playerColumn) override; - QRect rectForFloatPlayer( - Window::Column myColumn, - Window::Column playerColumn) const override; + bool wheelEventFromFloatPlayer(QEvent *e) override; + QRect rectForFloatPlayer() const override; protected: void resizeEvent(QResizeEvent *e) override; diff --git a/Telegram/SourceFiles/info/info_side_wrap.cpp b/Telegram/SourceFiles/info/info_side_wrap.cpp index 6a89f7bc9..c6506fc9a 100644 --- a/Telegram/SourceFiles/info/info_side_wrap.cpp +++ b/Telegram/SourceFiles/info/info_side_wrap.cpp @@ -25,6 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "info/info_media_widget.h" #include "info/info_memento.h" #include "ui/widgets/discrete_sliders.h" +#include "auth_session.h" #include "ui/widgets/shadow.h" #include "lang/lang_keys.h" #include "styles/style_info.h" @@ -80,8 +81,7 @@ void SideWrap::showTab(Tab tab) { showContent(createContent(tab)); } -void SideWrap::showContent(object_ptr content) { - auto section = content->section(); +void SideWrap::setSection(const Section §ion) { switch (section.type()) { case Section::Type::Profile: setCurrentTab(Tab::Profile); @@ -102,7 +102,9 @@ void SideWrap::showContent(object_ptr content) { setCurrentTab(Tab::None); break; } +} +void SideWrap::showContent(object_ptr content) { _content = std::move(content); _content->setGeometry(contentGeometry()); _content->show(); @@ -158,6 +160,9 @@ void SideWrap::doSetInnerFocus() { _content->setInnerFocus(); } +void SideWrap::showFinishedHook() { +} + bool SideWrap::showInternal( not_null memento) { if (auto infoMemento = dynamic_cast(memento.get())) { @@ -203,6 +208,8 @@ QRect SideWrap::contentGeometry() const { } void SideWrap::restoreState(not_null memento) { + // Validates contentGeometry(). + setSection(memento->section()); showContent(memento->content()->createWidget( this, Wrap::Side, @@ -211,7 +218,9 @@ void SideWrap::restoreState(not_null memento) { } void SideWrap::restoreState(not_null memento) { - showContent(memento->content(this, Wrap::Side)); + auto content = memento->content(this, Wrap::Side); + setSection(content->section()); + showContent(std::move(content)); } void SideWrap::setCurrentTab(Tab tab) { @@ -235,20 +244,20 @@ void SideWrap::resizeEvent(QResizeEvent *e) { } void SideWrap::paintEvent(QPaintEvent *e) { + SectionWidget::paintEvent(e); + if (animating()) { + return; + } + Painter p(this); p.fillRect(e->rect(), st::profileBg); } -bool SideWrap::wheelEventFromFloatPlayer( - QEvent *e, - Window::Column myColumn, - Window::Column playerColumn) { +bool SideWrap::wheelEventFromFloatPlayer(QEvent *e) { return _content->wheelEventFromFloatPlayer(e); } -QRect SideWrap::rectForFloatPlayer( - Window::Column myColumn, - Window::Column playerColumn) const { +QRect SideWrap::rectForFloatPlayer() const { return _content->rectForFloatPlayer(); } diff --git a/Telegram/SourceFiles/info/info_side_wrap.h b/Telegram/SourceFiles/info/info_side_wrap.h index ff446b89b..5ea6d9361 100644 --- a/Telegram/SourceFiles/info/info_side_wrap.h +++ b/Telegram/SourceFiles/info/info_side_wrap.h @@ -37,6 +37,7 @@ namespace Media { class Widget; } // namespace Media +class Section; class Memento; class MoveMemento; class ContentWidget; @@ -75,19 +76,15 @@ public: not_null memento); // Float player interface. - bool wheelEventFromFloatPlayer( - QEvent *e, - Window::Column myColumn, - Window::Column playerColumn) override; - QRect rectForFloatPlayer( - Window::Column myColumn, - Window::Column playerColumn) const override; + bool wheelEventFromFloatPlayer(QEvent *e) override; + QRect rectForFloatPlayer() const override; protected: void resizeEvent(QResizeEvent *e) override; void paintEvent(QPaintEvent *e) override; void doSetInnerFocus() override; + void showFinishedHook() override; private: enum class Tab { @@ -105,6 +102,7 @@ private: void setupTabs(); void showTab(Tab tab); void setCurrentTab(Tab tab); + void setSection(const Section §ion); void showContent(object_ptr content); object_ptr createContent(Tab tab); object_ptr createProfileWidget(); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 5c48b624b..0b5b25444 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -168,6 +168,15 @@ MainWidget::MainWidget( subscribe(_controller->floatPlayerAreaUpdated(), [this] { checkFloatPlayerVisibility(); }); + subscribe(_controller->historyPeerChanged(), [this](PeerData *peer) { + if (!peer) { + _thirdSection.destroy(); + _thirdShadow.destroy(); + } else if (Adaptive::ThreeColumn() + && Auth().data().thirdSectionInfoEnabled()) { + _controller->showPeerInfo(peer, anim::type::instant); + } + }); QCoreApplication::instance()->installEventFilter(this); @@ -355,9 +364,8 @@ QPoint MainWidget::getFloatPlayerHiddenPosition(QPoint position, QSize size, Rec } QPoint MainWidget::getFloatPlayerPosition(not_null instance) const { - auto column = instance->column; - auto section = getFloatPlayerSection(&column); - auto rect = section->rectForFloatPlayer(column, instance->column); + auto section = getFloatPlayerSection(instance->column); + auto rect = section->rectForFloatPlayer(); auto position = rect.topLeft(); if (IsBottomCorner(instance->corner)) { position.setY(position.y() + rect.height() - instance->widget->height()); @@ -398,30 +406,39 @@ void MainWidget::removeFloatPlayer(not_null instance) { widget.destroy(); } -Window::AbstractSectionWidget *MainWidget::getFloatPlayerSection(not_null column) const { - if (!Adaptive::Normal()) { - *column = Adaptive::OneColumn() ? Window::Column::First : Window::Column::Second; - if (Adaptive::OneColumn() && selectingPeer()) { +Window::AbstractSectionWidget *MainWidget::getFloatPlayerSection(Window::Column column) const { + if (Adaptive::ThreeColumn()) { + if (column == Window::Column::First) { return _dialogs; - } else if (_overview) { - return _overview; - } else if (_wideSection) { - return _wideSection; - } else if (!Adaptive::OneColumn() || _history->peer()) { + } else if (column == Window::Column::Second + || !_thirdSection) { + if (_mainSection) { + return _mainSection; + } return _history; } - return _dialogs; + return _thirdSection; + } else if (Adaptive::Normal()) { + if (column == Window::Column::First) { + return _dialogs; + } + if (_overview) { + return _overview; + } else if (_mainSection) { + return _mainSection; + } + return _history; } - if (*column == Window::Column::First) { + if (Adaptive::OneColumn() && selectingPeer()) { return _dialogs; - } - *column = Window::Column::Second; - if (_overview) { + } else if (_overview) { return _overview; - } else if (_wideSection) { - return _wideSection; + } else if (_mainSection) { + return _mainSection; + } else if (!Adaptive::OneColumn() || _history->peer()) { + return _history; } - return _history; + return _dialogs; } void MainWidget::updateFloatPlayerColumnCorner(QPoint center) { @@ -430,47 +447,58 @@ void MainWidget::updateFloatPlayerColumnCorner(QPoint center) { auto min = INT_MAX; auto column = Auth().data().floatPlayerColumn(); auto corner = Auth().data().floatPlayerCorner(); - auto checkSection = [this, center, size, &min, &column, &corner](Window::AbstractSectionWidget *widget, Window::Column myColumn, Window::Column playerColumn) { - auto rect = mapFromGlobal(widget->rectForFloatPlayer(myColumn, playerColumn)); + auto checkSection = [this, center, size, &min, &column, &corner]( + Window::AbstractSectionWidget *widget, + Window::Column widgetColumn) { + auto rect = mapFromGlobal(widget->rectForFloatPlayer()); auto left = rect.x() + (size.width() / 2); auto right = rect.x() + rect.width() - (size.width() / 2); auto top = rect.y() + (size.height() / 2); auto bottom = rect.y() + rect.height() - (size.height() / 2); - auto checkCorner = [this, playerColumn, &min, &column, &corner](int distance, RectPart checked) { + auto checkCorner = [&](QPoint point, RectPart checked) { + auto distance = (point - center).manhattanLength(); if (min > distance) { min = distance; - column = playerColumn; + column = widgetColumn; corner = checked; } }; - checkCorner((QPoint(left, top) - center).manhattanLength(), RectPart::TopLeft); - checkCorner((QPoint(right, top) - center).manhattanLength(), RectPart::TopRight); - checkCorner((QPoint(left, bottom) - center).manhattanLength(), RectPart::BottomLeft); - checkCorner((QPoint(right, bottom) - center).manhattanLength(), RectPart::BottomRight); + checkCorner({ left, top }, RectPart::TopLeft); + checkCorner({ right, top }, RectPart::TopRight); + checkCorner({ left, bottom }, RectPart::BottomLeft); + checkCorner({ right, bottom }, RectPart::BottomRight); }; - if (!Adaptive::Normal()) { - if (Adaptive::OneColumn() && selectingPeer()) { - checkSection(_dialogs, Window::Column::First, Window::Column::First); - } else if (_overview) { - checkSection(_overview, Window::Column::Second, Window::Column::Second); - } else if (_wideSection) { - checkSection(_wideSection, Window::Column::Second, Window::Column::Second); - } else if (!Adaptive::OneColumn() || _history->peer()) { - checkSection(_history, Window::Column::Second, Window::Column::Second); - checkSection(_history, Window::Column::Second, Window::Column::Third); + if (Adaptive::ThreeColumn()) { + checkSection(_dialogs, Window::Column::First); + if (_mainSection) { + checkSection(_mainSection, Window::Column::Second); } else { - checkSection(_dialogs, Window::Column::First, Window::Column::First); + checkSection(_history, Window::Column::Second); + } + if (_thirdSection) { + checkSection(_thirdSection, Window::Column::Third); + } + } else if (Adaptive::Normal()) { + checkSection(_dialogs, Window::Column::First); + if (_overview) { + checkSection(_overview, Window::Column::Second); + } else if (_mainSection) { + checkSection(_mainSection, Window::Column::Second); + } else { + checkSection(_history, Window::Column::Second); } } else { - checkSection(_dialogs, Window::Column::First, Window::Column::First); - if (_overview) { - checkSection(_overview, Window::Column::Second, Window::Column::Second); - } else if (_wideSection) { - checkSection(_wideSection, Window::Column::Second, Window::Column::Second); + if (Adaptive::OneColumn() && selectingPeer()) { + checkSection(_dialogs, Window::Column::First); + } else if (_overview) { + checkSection(_overview, Window::Column::Second); + } else if (_mainSection) { + checkSection(_mainSection, Window::Column::Second); + } else if (!Adaptive::OneColumn() || _history->peer()) { + checkSection(_history, Window::Column::Second); } else { - checkSection(_history, Window::Column::Second, Window::Column::Second); - checkSection(_history, Window::Column::Second, Window::Column::Third); + checkSection(_dialogs, Window::Column::First); } } if (Auth().data().floatPlayerColumn() != column) { @@ -833,8 +861,8 @@ void MainWidget::notify_historyMuteUpdated(History *history) { bool MainWidget::cmd_search() { if (Ui::isLayerShown() || !isActiveWindow()) return false; - if (_wideSection) { - return _wideSection->cmd_search(); + if (_mainSection) { + return _mainSection->cmd_search(); } return _history->cmd_search(); } @@ -858,20 +886,20 @@ void MainWidget::noHider(HistoryHider *destroyed) { _forwardConfirm = nullptr; } onHistoryShown(_history->history(), _history->msgId()); - if (_wideSection || _overview || (_history->peer() && _history->peer()->id)) { + if (_mainSection || _overview || (_history->peer() && _history->peer()->id)) { auto animationParams = ([this] { if (_overview) { return prepareOverviewAnimation(); - } else if (_wideSection) { - return prepareWideSectionAnimation(_wideSection); + } else if (_mainSection) { + return prepareMainSectionAnimation(_mainSection); } return prepareHistoryAnimation(_history->peer() ? _history->peer()->id : 0); })(); _dialogs->hide(); if (_overview) { _overview->showAnimated(Window::SlideDirection::FromRight, animationParams); - } else if (_wideSection) { - _wideSection->showAnimated(Window::SlideDirection::FromRight, animationParams); + } else if (_mainSection) { + _mainSection->showAnimated(Window::SlideDirection::FromRight, animationParams); } else { _history->showAnimated(Window::SlideDirection::FromRight, animationParams); } @@ -902,8 +930,8 @@ void MainWidget::hiderLayer(object_ptr h) { onHistoryShown(0, 0); if (_overview) { _overview->hide(); - } else if (_wideSection) { - _wideSection->hide(); + } else if (_mainSection) { + _mainSection->hide(); } else { _history->hide(); } @@ -2178,8 +2206,8 @@ void MainWidget::setInnerFocus() { _hider->setFocus(); } else if (!_hider && _overview) { _overview->activate(); - } else if (!_hider && _wideSection) { - _wideSection->setInnerFocus(); + } else if (!_hider && _mainSection) { + _mainSection->setInnerFocus(); } else if (!_hider && _thirdSection) { _thirdSection->setInnerFocus(); } else { @@ -2187,12 +2215,12 @@ void MainWidget::setInnerFocus() { } } else if (_overview) { _overview->activate(); - } else if (_wideSection) { - _wideSection->setInnerFocus(); - } else if (_thirdSection) { - _thirdSection->setInnerFocus(); - } else { + } else if (_mainSection) { + _mainSection->setInnerFocus(); + } else if (_history->peer() || !_thirdSection) { _history->setInnerFocus(); + } else { + _thirdSection->setInnerFocus(); } } @@ -2499,7 +2527,7 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, Ui::Show } } if (_history->isHidden()) { - return (_wideSection != nullptr) + return (_mainSection != nullptr) || (_overview != nullptr) || (Adaptive::OneColumn() && !_dialogs->isHidden()); } @@ -2528,11 +2556,11 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, Ui::Show auto noPeer = !_history->peer(); auto onlyDialogs = noPeer && Adaptive::OneColumn(); - if (_wideSection || _overview) { - if (_wideSection) { - _wideSection->hide(); - _wideSection->deleteLater(); - _wideSection = nullptr; + if (_mainSection || _overview) { + if (_mainSection) { + _mainSection->hide(); + _mainSection->deleteLater(); + _mainSection = nullptr; } if (_overview) { _overview->hide(); @@ -2557,14 +2585,19 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, Ui::Show } else { if (!noPeer && wasActivePeer != activePeer()) { if (activePeer()->isChannel()) { - activePeer()->asChannel()->ptsWaitingForShortPoll(WaitForChannelGetDifference); + activePeer()->asChannel()->ptsWaitingForShortPoll( + WaitForChannelGetDifference); } _viewsIncremented.remove(activePeer()); } if (Adaptive::OneColumn() && !_dialogs->isHidden()) _dialogs->hide(); if (!_a_show.animating()) { if (!animationParams.oldContentCache.isNull()) { - _history->showAnimated(back ? Window::SlideDirection::FromLeft : Window::SlideDirection::FromRight, animationParams); + _history->showAnimated( + back + ? Window::SlideDirection::FromLeft + : Window::SlideDirection::FromRight, + animationParams); } else { _history->show(); if (App::wnd()) { @@ -2635,13 +2668,23 @@ bool MainWidget::showMediaTypeSwitch() const { void MainWidget::saveSectionInStack() { if (_overview) { - _stack.push_back(std::make_unique(_overview->peer(), _overview->type(), _overview->lastWidth(), _overview->lastScrollTop())); - } else if (_wideSection) { - _stack.push_back(std::make_unique(_wideSection->createMemento())); + _stack.push_back(std::make_unique( + _overview->peer(), + _overview->type(), + _overview->lastWidth(), + _overview->lastScrollTop())); + } else if (_mainSection) { + if (auto memento = _mainSection->createMemento()) { + _stack.push_back(std::make_unique( + std::move(memento))); + } } else if (_history->peer()) { _peerInStack = _history->peer(); _msgIdInStack = _history->msgId(); - _stack.push_back(std::make_unique(_peerInStack, _msgIdInStack, _history->replyReturns())); + _stack.push_back(std::make_unique( + _peerInStack, + _msgIdInStack, + _history->replyReturns())); } } @@ -2667,7 +2710,7 @@ void MainWidget::showMediaOverview(PeerData *peer, MediaOverviewType type, bool if (_a_show.animating() || App::passcoded()) { return false; } - if (Adaptive::OneColumn() || isSectionShown()) { + if (Adaptive::OneColumn() || isMainSectionShown()) { return true; } return false; @@ -2684,10 +2727,10 @@ void MainWidget::showMediaOverview(PeerData *peer, MediaOverviewType type, bool _overview->deleteLater(); _overview->rpcClear(); } - if (_wideSection) { - _wideSection->hide(); - _wideSection->deleteLater(); - _wideSection = nullptr; + if (_mainSection) { + _mainSection->hide(); + _mainSection->deleteLater(); + _mainSection = nullptr; } _overview.create(this, _controller, peer, type); updateControlsGeometry(); @@ -2716,30 +2759,61 @@ void MainWidget::showMediaOverview(PeerData *peer, MediaOverviewType type, bool orderWidgets(); } -void MainWidget::showWideSection(Window::SectionMemento &&memento) { - Ui::hideSettingsAndLayer(); - if (_wideSection && _wideSection->showInternal(&memento)) { +void MainWidget::showSection( + Window::SectionMemento &&memento, + anim::type animated) { + if (_mainSection && _mainSection->showInternal(&memento)) { + return; + } else if (_thirdSection && _thirdSection->showInternal(&memento)) { return; } - showNewWideSection(std::move(memento), false, true); + + // If the window was not resized, but we've enabled + // tabbedSelectorSectionEnabled or thirdSectionInfoEnabled + // we need to update adaptive layout to Adaptive::ThirdColumn(). + updateColumnLayout(); + + showNewSection(std::move(memento), false, true, animated); } -Window::SectionSlideParams MainWidget::prepareShowAnimation(bool willHaveTopBarShadow, bool willHaveTabbedSection) { +void MainWidget::updateColumnLayout() { + updateWindowAdaptiveLayout(); +} + +Window::SectionSlideParams MainWidget::prepareThirdSectionAnimation(Window::SectionWidget *section) { + Expects(_thirdSection != nullptr); + + Window::SectionSlideParams result; + result.withTopBarShadow = section->hasTopBarShadow(); + if (!_thirdSection->hasTopBarShadow()) { + result.withTopBarShadow = false; + } + for (auto &instance : _playerFloats) { + instance->widget->hide(); + } + auto sectionTop = getThirdSectionTop(); + result.oldContentCache = _thirdSection->grabForShowAnimation(result); + for (auto &instance : _playerFloats) { + if (instance->visible) { + instance->widget->show(); + } + } + return result; +} + +Window::SectionSlideParams MainWidget::prepareShowAnimation( + bool willHaveTopBarShadow) { Window::SectionSlideParams result; result.withTopBarShadow = willHaveTopBarShadow; - result.withTabbedSection = willHaveTabbedSection; if (selectingPeer() && Adaptive::OneColumn()) { result.withTopBarShadow = false; - } else if (_wideSection) { - if (!_wideSection->hasTopBarShadow()) { + } else if (_mainSection) { + if (!_mainSection->hasTopBarShadow()) { result.withTopBarShadow = false; } } else if (!_overview && !_history->peer()) { result.withTopBarShadow = false; } - if ((selectingPeer() && Adaptive::OneColumn()) || !_history->peer()) { - result.withTabbedSection = false; - } for (auto &instance : _playerFloats) { instance->widget->hide(); @@ -2760,11 +2834,11 @@ Window::SectionSlideParams MainWidget::prepareShowAnimation(bool willHaveTopBarS _playerPlaylist->hide(); } - auto sectionTop = getSectionTop(); + auto sectionTop = getMainSectionTop(); if (selectingPeer() && Adaptive::OneColumn()) { result.oldContentCache = myGrab(this, QRect(0, sectionTop, _dialogsWidth, height() - sectionTop)); - } else if (_wideSection) { - result.oldContentCache = _wideSection->grabForShowAnimation(result); + } else if (_mainSection) { + result.oldContentCache = _mainSection->grabForShowAnimation(result); } else { if (result.withTopBarShadow) { if (_overview) _overview->grapWithoutTopBarShadow(); @@ -2777,8 +2851,14 @@ Window::SectionSlideParams MainWidget::prepareShowAnimation(bool willHaveTopBarS result.oldContentCache = myGrab(this, QRect(0, sectionTop, _dialogsWidth, height() - sectionTop)); } else { _sideShadow->hide(); + if (_thirdShadow) { + _thirdShadow->hide(); + } result.oldContentCache = myGrab(this, QRect(_dialogsWidth, sectionTop, width() - _dialogsWidth, height() - sectionTop)); _sideShadow->show(); + if (_thirdShadow) { + _thirdShadow->show(); + } } if (_overview) _overview->grabFinish(); _history->grabFinish(); @@ -2805,41 +2885,90 @@ Window::SectionSlideParams MainWidget::prepareShowAnimation(bool willHaveTopBarS return result; } -Window::SectionSlideParams MainWidget::prepareWideSectionAnimation(Window::SectionWidget *section) { - return prepareShowAnimation(section->hasTopBarShadow(), false); +Window::SectionSlideParams MainWidget::prepareMainSectionAnimation(Window::SectionWidget *section) { + return prepareShowAnimation(section->hasTopBarShadow()); } Window::SectionSlideParams MainWidget::prepareHistoryAnimation(PeerId historyPeerId) { - return prepareShowAnimation(historyPeerId != 0, historyPeerId != 0); + return prepareShowAnimation(historyPeerId != 0); } Window::SectionSlideParams MainWidget::prepareOverviewAnimation() { - return prepareShowAnimation(true, false); + return prepareShowAnimation(true); } Window::SectionSlideParams MainWidget::prepareDialogsAnimation() { - return prepareShowAnimation(false, false); + return prepareShowAnimation(false); } -void MainWidget::showNewWideSection(Window::SectionMemento &&memento, bool back, bool saveInStack) { +void MainWidget::showNewSection( + Window::SectionMemento &&memento, + bool back, + bool saveInStack, + anim::type animated) { + using Column = Window::Column; + + auto thirdSectionTop = getThirdSectionTop(); + auto newThirdGeometry = QRect( + width() - st::columnMinimalWidthThird, + thirdSectionTop, + st::columnMinimalWidthThird, + height() - thirdSectionTop); + auto newThirdSection = Adaptive::ThreeColumn() + ? memento.createWidget( + this, + _controller, + Column::Third, + newThirdGeometry) + : nullptr; + if (newThirdSection) { + saveInStack = false; + } else { + if (auto layer = memento.createLayer(_controller)) { + _controller->showSpecialLayer(std::move(layer)); + return; + } + } + QPixmap animCache; _controller->dialogsListFocused().set(false, true); _a_dialogsWidth.finish(); - auto sectionTop = getSectionTop(); - auto newWideGeometry = QRect(_history->x(), sectionTop, _history->width(), height() - sectionTop); - auto newWideSection = memento.createWidget(this, _controller, newWideGeometry); + auto mainSectionTop = getMainSectionTop(); + auto newMainGeometry = QRect( + _history->x(), + mainSectionTop, + _history->width(), + height() - mainSectionTop); + auto newMainSection = newThirdSection + ? nullptr + : memento.createWidget( + this, + _controller, + Adaptive::OneColumn() ? Column::First : Column::Second, + newMainGeometry); + Assert(newMainSection || newThirdSection); + auto animatedShow = [&] { - if (_a_show.animating() || App::passcoded() || memento.instant()) { + if (_a_show.animating() + || App::passcoded() + || (animated == anim::type::instant) + || memento.instant()) { return false; } - if (Adaptive::OneColumn() || isSectionShown()) { + if (Adaptive::OneColumn() + || (newThirdSection && _thirdSection) + || (newMainSection && isMainSectionShown())) { return true; } return false; }(); - auto animationParams = animatedShow ? prepareWideSectionAnimation(newWideSection) : Window::SectionSlideParams(); + auto animationParams = animatedShow + ? (newThirdSection + ? prepareThirdSectionAnimation(newThirdSection) + : prepareMainSectionAnimation(newMainSection)) + : Window::SectionSlideParams(); setFocus(); // otherwise dialogs widget could be focused. @@ -2854,52 +2983,70 @@ void MainWidget::showNewWideSection(Window::SectionMemento &&memento, bool back, _overview->rpcClear(); _overview = nullptr; } - if (_wideSection) { - _wideSection->hide(); - _wideSection->deleteLater(); - _wideSection = nullptr; + auto &settingSection = newThirdSection + ? _thirdSection + : _mainSection; + if (newThirdSection) { + _thirdSection = std::move(newThirdSection); + if (!_thirdShadow) { + _thirdShadow.create(this, st::shadowFg); + _thirdShadow->show(); + orderWidgets(); + } + updateControlsGeometry(); + } else { + if (_mainSection) { + _mainSection->hide(); + _mainSection->deleteLater(); + _mainSection = nullptr; + } + _mainSection = std::move(newMainSection); + updateControlsGeometry(); + _history->finishAnimation(); + _history->showHistory(0, 0); + _history->hide(); + if (Adaptive::OneColumn()) _dialogs->hide(); } - _wideSection = std::move(newWideSection); - - updateControlsGeometry(); - _history->finishAnimation(); - _history->showHistory(0, 0); - _history->hide(); - if (Adaptive::OneColumn()) _dialogs->hide(); if (animationParams) { - auto direction = back ? Window::SlideDirection::FromLeft : Window::SlideDirection::FromRight; - _wideSection->showAnimated(direction, animationParams); + auto direction = (back || settingSection->forceAnimateBack()) + ? Window::SlideDirection::FromLeft + : Window::SlideDirection::FromRight; + settingSection->showAnimated(direction, animationParams); } else { - _wideSection->showFast(); + settingSection->showFast(); } checkFloatPlayerVisibility(); orderWidgets(); } -void MainWidget::checkWideSectionToLayer() { - if (!_wideSection) { +void MainWidget::checkMainSectionToLayer() { + if (!_mainSection) { return; } - if (auto layer = _wideSection->moveContentToLayer(width())) { - dropWideSection(_wideSection); + if (auto layer = _mainSection->moveContentToLayer(width())) { + dropMainSection(_mainSection); _controller->showSpecialLayer( std::move(layer), LayerOption::ForceFast); } } -void MainWidget::dropWideSection(Window::SectionWidget *widget) { - if (_wideSection != widget) { +void MainWidget::dropMainSection(Window::SectionWidget *widget) { + if (_mainSection != widget) { return; } - _wideSection.destroy(); + _mainSection.destroy(); showBackFromStack(); } -bool MainWidget::isSectionShown() const { - return _wideSection || _overview || _history->peer(); +bool MainWidget::isMainSectionShown() const { + return _mainSection || _overview || _history->peer(); +} + +bool MainWidget::isThirdSectionShown() const { + return _thirdSection != nullptr; } bool MainWidget::stackIsEmpty() const { @@ -2936,7 +3083,11 @@ void MainWidget::showBackFromStack() { _history->setReplyReturns(historyItem->peer->id, historyItem->replyReturns); } else if (item->type() == SectionStackItem) { auto sectionItem = static_cast(item.get()); - showNewWideSection(std::move(*sectionItem->memento()), true, false); + showNewSection( + std::move(*sectionItem->memento()), + true, + false, + anim::type::normal); } else if (item->type() == OverviewStackItem) { auto overviewItem = static_cast(item.get()); showMediaOverview(overviewItem->peer, overviewItem->mediaType, true, overviewItem->lastScrollTop); @@ -2955,6 +3106,9 @@ void MainWidget::orderWidgets() { _playerVolume->raise(); } _sideShadow->raise(); + if (_thirdShadow) { + _thirdShadow->raise(); + } _sideResizeArea->raise(); _playerPlaylist->raise(); _playerPanel->raise(); @@ -2992,13 +3146,19 @@ QPixmap MainWidget::grabForShowAnimation(const Window::SectionSlideParams ¶m _playerPlaylist->hide(); } - auto sectionTop = getSectionTop(); + auto sectionTop = getMainSectionTop(); if (Adaptive::OneColumn()) { result = myGrab(this, QRect(0, sectionTop, _dialogsWidth, height() - sectionTop)); } else { _sideShadow->hide(); + if (_thirdShadow) { + _thirdShadow->hide(); + } result = myGrab(this, QRect(_dialogsWidth, sectionTop, width() - _dialogsWidth, height() - sectionTop)); _sideShadow->show(); + if (_thirdShadow) { + _thirdShadow->show(); + } } if (playerVolumeVisible) { _playerVolume->show(); @@ -3126,20 +3286,30 @@ void MainWidget::paintEvent(QPaintEvent *e) { } } -int MainWidget::getSectionTop() const { +int MainWidget::getMainSectionTop() const { return _callTopBarHeight + _playerHeight; } +int MainWidget::getThirdSectionTop() const { + return 0; +} + void MainWidget::hideAll() { _dialogs->hide(); _history->hide(); - if (_wideSection) { - _wideSection->hide(); + if (_mainSection) { + _mainSection->hide(); + } + if (_thirdSection) { + _thirdSection->hide(); } if (_overview) { _overview->hide(); } _sideShadow->hide(); + if (_thirdShadow) { + _thirdShadow->hide(); + } if (_player) { _player->hide(); _playerHeight = 0; @@ -3172,11 +3342,11 @@ void MainWidget::showAll() { _dialogs->showFast(); _history->hide(); if (_overview) _overview->hide(); - if (_wideSection) _wideSection->hide(); + if (_mainSection) _mainSection->hide(); } else if (_overview) { _overview->show(); - } else if (_wideSection) { - _wideSection->show(); + } else if (_mainSection) { + _mainSection->show(); } else if (_history->peer()) { _history->show(); _history->updateControlsGeometry(); @@ -3185,9 +3355,9 @@ void MainWidget::showAll() { _history->hide(); } if (!selectingPeer()) { - if (_wideSection) { + if (_mainSection) { _dialogs->hide(); - } else if (isSectionShown()) { + } else if (isMainSectionShown()) { _dialogs->hide(); } } @@ -3206,12 +3376,18 @@ void MainWidget::showAll() { _dialogs->showFast(); if (_overview) { _overview->show(); - } else if (_wideSection) { - _wideSection->show(); + } else if (_mainSection) { + _mainSection->show(); } else { _history->show(); _history->updateControlsGeometry(); } + if (_thirdSection) { + _thirdSection->show(); + } + if (_thirdShadow) { + _thirdShadow->show(); + } } if (_player) { _player->show(); @@ -3240,7 +3416,19 @@ void MainWidget::updateControlsGeometry() { if (!_a_dialogsWidth.animating()) { _dialogs->stopWidthAnimation(); } - auto sectionTop = getSectionTop(); + if (Adaptive::ThreeColumn()) { + if (!_thirdSection) { + if (Auth().data().tabbedSelectorSectionEnabled()) { + _history->pushTabbedSelectorToThirdSection(); + } else if (Auth().data().thirdSectionInfoEnabled()) { + _history->pushInfoToThirdSection(); + } + } + } else { + _thirdSection.destroy(); + _thirdShadow.destroy(); + } + auto mainSectionTop = getMainSectionTop(); auto dialogsWidth = qRound(_a_dialogsWidth.current(_dialogsWidth)); if (Adaptive::OneColumn()) { if (_callTopBar) { @@ -3251,42 +3439,65 @@ void MainWidget::updateControlsGeometry() { _player->resizeToWidth(dialogsWidth); _player->moveToLeft(0, _callTopBarHeight); } - _dialogs->setGeometry(0, sectionTop, dialogsWidth, height() - sectionTop); - _history->setGeometry(0, sectionTop, dialogsWidth, height() - sectionTop); + auto mainSectionGeometry = QRect( + 0, + mainSectionTop, + dialogsWidth, + height() - mainSectionTop); + _dialogs->setGeometry(mainSectionGeometry); + _history->setGeometry(mainSectionGeometry); if (_hider) _hider->setGeometry(0, 0, dialogsWidth, height()); } else { - accumulate_min(dialogsWidth, width() - st::windowMinWidth); - auto sectionWidth = width() - dialogsWidth; + auto thirdSectionWidth = _thirdSection ? _thirdSection->width() : 0; + if (_thirdSection) { + auto thirdSectionTop = getThirdSectionTop(); + accumulate_min(thirdSectionWidth, width() - st::columnMinimalWidthMain - st::columnMinimalWidthLeft); + accumulate_max(thirdSectionWidth, st::columnMinimalWidthThird); + _thirdSection->setGeometry( + width() - thirdSectionWidth, + thirdSectionTop, + thirdSectionWidth, + height() - thirdSectionTop); + } + accumulate_min(dialogsWidth, width() - st::columnMinimalWidthMain); + auto mainSectionWidth = width() - dialogsWidth - thirdSectionWidth; _dialogs->setGeometryToLeft(0, 0, dialogsWidth, height()); _sideShadow->setGeometryToLeft(dialogsWidth, 0, st::lineWidth, height()); + if (_thirdShadow) { + _thirdShadow->setGeometryToLeft( + width() - thirdSectionWidth - st::lineWidth, + 0, + st::lineWidth, + height()); + } if (_callTopBar) { - _callTopBar->resizeToWidth(sectionWidth); + _callTopBar->resizeToWidth(mainSectionWidth); _callTopBar->moveToLeft(dialogsWidth, 0); } if (_player) { - _player->resizeToWidth(sectionWidth); + _player->resizeToWidth(mainSectionWidth); _player->moveToLeft(dialogsWidth, _callTopBarHeight); } - _history->setGeometryToLeft(dialogsWidth, sectionTop, sectionWidth, height() - sectionTop); + _history->setGeometryToLeft(dialogsWidth, mainSectionTop, mainSectionWidth, height() - mainSectionTop); if (_hider) { - _hider->setGeometryToLeft(dialogsWidth, 0, sectionWidth, height()); + _hider->setGeometryToLeft(dialogsWidth, 0, mainSectionWidth, height()); } } _sideResizeArea->setGeometryToLeft(_history->x(), 0, st::historyResizeWidth, height()); auto isSideResizeAreaVisible = [this] { - if (width() < st::windowMinWidth + st::dialogsWidthMin) { + if (width() < st::columnMinimalWidthLeft + st::columnMinimalWidthMain) { return false; } - if (Adaptive::OneColumn() && !isSectionShown()) { + if (Adaptive::OneColumn() && !isMainSectionShown()) { return false; } return true; }; _sideResizeArea->setVisible(isSideResizeAreaVisible()); - if (_wideSection) { - auto wideSectionGeometry = QRect(_history->x(), sectionTop, _history->width(), height() - sectionTop); - _wideSection->setGeometryWithTopMoved(wideSectionGeometry, _contentScrollAddToY); + if (_mainSection) { + auto mainSectionGeometry = QRect(_history->x(), mainSectionTop, _history->width(), height() - mainSectionTop); + _mainSection->setGeometryWithTopMoved(mainSectionGeometry, _contentScrollAddToY); } if (_overview) _overview->setGeometry(_history->geometry()); updateMediaPlayerPosition(); @@ -3364,7 +3575,8 @@ bool MainWidget::eventFilter(QObject *o, QEvent *e) { if (auto widget = qobject_cast(o)) { if (_history == widget || _history->isAncestorOf(widget) || (_overview && (_overview == widget || _overview->isAncestorOf(widget))) - || (_wideSection && (_wideSection == widget || _wideSection->isAncestorOf(widget)))) { + || (_mainSection && (_mainSection == widget || _mainSection->isAncestorOf(widget))) + || (_thirdSection && (_thirdSection == widget || _thirdSection->isAncestorOf(widget)))) { _controller->dialogsListFocused().set(false); } else if (_dialogs == widget || _dialogs->isAncestorOf(widget)) { _controller->dialogsListFocused().set(true); @@ -3378,9 +3590,9 @@ bool MainWidget::eventFilter(QObject *o, QEvent *e) { } else if (e->type() == QEvent::Wheel && !_playerFloats.empty()) { for (auto &instance : _playerFloats) { if (instance->widget == o) { - auto column = instance->column; - auto section = getFloatPlayerSection(&column); - return section->wheelEventFromFloatPlayer(e, column, instance->column); + auto section = getFloatPlayerSection( + instance->column); + return section->wheelEventFromFloatPlayer(e); } } } @@ -3403,14 +3615,16 @@ void MainWidget::updateWindowAdaptiveLayout() { // for the normal layout. If so, switch to the normal layout. if (layout.windowLayout == Adaptive::WindowLayout::OneColumn) { auto chatWidth = layout.chatWidth; - if (Auth().data().tabbedSelectorSectionEnabled() - && chatWidth >= _history->minimalWidthForTabbedSelectorSection()) { - chatWidth -= _history->tabbedSelectorSectionWidth(); - } - if (chatWidth >= st::dialogsWidthMin + st::windowMinWidth) { + //if (Auth().data().tabbedSelectorSectionEnabled() + // && chatWidth >= _history->minimalWidthForTabbedSelectorSection()) { + // chatWidth -= _history->tabbedSelectorSectionWidth(); + //} + auto minimalNormalWidth = st::columnMinimalWidthLeft + + st::columnMinimalWidthMain; + if (chatWidth >= minimalNormalWidth) { // Switch layout back to normal in a wide enough window. layout.windowLayout = Adaptive::WindowLayout::Normal; - layout.dialogsWidth = st::dialogsWidthMin; + layout.dialogsWidth = st::columnMinimalWidthLeft; layout.chatWidth = layout.bodyWidth - layout.dialogsWidth; dialogsWidthRatio = float64(layout.dialogsWidth) / layout.bodyWidth; } @@ -3419,23 +3633,23 @@ void MainWidget::updateWindowAdaptiveLayout() { // Check if we are going to create the third column and shrink the // dialogs widget to provide a wide enough chat history column. // Don't shrink the column on the first call, when window is inited. - if (layout.windowLayout == Adaptive::WindowLayout::Normal + if (layout.windowLayout == Adaptive::WindowLayout::ThreeColumn && _started && _controller->window()->positionInited()) { - auto chatWidth = layout.chatWidth; - if (_history->willSwitchToTabbedSelectorWithWidth(chatWidth)) { - auto thirdColumnWidth = _history->tabbedSelectorSectionWidth(); - auto twoColumnsWidth = (layout.bodyWidth - thirdColumnWidth); - auto sameRatioChatWidth = twoColumnsWidth - qRound(dialogsWidthRatio * twoColumnsWidth); - auto desiredChatWidth = qMax(sameRatioChatWidth, HistoryLayout::WideChatWidth()); - chatWidth -= thirdColumnWidth; - auto extendChatBy = desiredChatWidth - chatWidth; - accumulate_min(extendChatBy, layout.dialogsWidth - st::dialogsWidthMin); - if (extendChatBy > 0) { - layout.dialogsWidth -= extendChatBy; - layout.chatWidth += extendChatBy; - dialogsWidthRatio = float64(layout.dialogsWidth) / layout.bodyWidth; - } - } + //auto chatWidth = layout.chatWidth; + //if (_history->willSwitchToTabbedSelectorWithWidth(chatWidth)) { + // auto thirdColumnWidth = _history->tabbedSelectorSectionWidth(); + // auto twoColumnsWidth = (layout.bodyWidth - thirdColumnWidth); + // auto sameRatioChatWidth = twoColumnsWidth - qRound(dialogsWidthRatio * twoColumnsWidth); + // auto desiredChatWidth = qMax(sameRatioChatWidth, HistoryLayout::WideChatWidth()); + // chatWidth -= thirdColumnWidth; + // auto extendChatBy = desiredChatWidth - chatWidth; + // accumulate_min(extendChatBy, layout.dialogsWidth - st::columnMinimalWidthLeft); + // if (extendChatBy > 0) { + // layout.dialogsWidth -= extendChatBy; + // layout.chatWidth += extendChatBy; + // dialogsWidthRatio = float64(layout.dialogsWidth) / layout.bodyWidth; + // } + //} } _controller->dialogsWidthRatio().set(dialogsWidthRatio, true); @@ -3450,27 +3664,27 @@ void MainWidget::updateWindowAdaptiveLayout() { bool MainWidget::paintTopBar(Painter &p, int decreaseWidth, TimeMs ms) { if (_overview) { return _overview->paintTopBar(p, decreaseWidth); - } else if (!_wideSection) { + } else if (!_mainSection) { return _history->paintTopBar(p, decreaseWidth, ms); } return false; } QRect MainWidget::getMembersShowAreaGeometry() const { - if (!_overview && !_wideSection) { + if (!_overview && !_mainSection) { return _history->getMembersShowAreaGeometry(); } return QRect(); } void MainWidget::setMembersShowAreaActive(bool active) { - if (!active || (!_overview && !_wideSection)) { + if (!active || (!_overview && !_mainSection)) { _history->setMembersShowAreaActive(active); } } int MainWidget::backgroundFromY() const { - return -getSectionTop(); + return -getMainSectionTop(); } void MainWidget::onHistoryShown(History *history, MsgId atMsgId) { @@ -4007,7 +4221,7 @@ void MainWidget::openPeerByName(const QString &username, MsgId msgId, const QStr // Always open bot chats, even from mention links. Ui::showPeerHistoryAsync(peer->id, ShowAtUnreadMsgId, Ui::ShowWay::Forward); } else { - Ui::showPeerProfile(peer); + _controller->showPeerInfo(peer); } } else { if (msgId == ShowAtProfileMsgId || !peer->isChannel()) { // show specific posts only in channels / supergroups @@ -4034,12 +4248,7 @@ void MainWidget::joinGroupByHash(const QString &hash) { void MainWidget::stickersBox(const MTPInputStickerSet &set) { Messenger::Instance().hideMediaView(); - auto box = Ui::show(Box(set)); - connect(box, SIGNAL(installed(uint64)), this, SLOT(onStickersInstalled(uint64))); -} - -void MainWidget::onStickersInstalled(uint64 setId) { - _history->stickersInstalled(setId); + Ui::show(Box(set)); } void MainWidget::onSelfParticipantUpdated(ChannelData *channel) { @@ -4090,7 +4299,7 @@ void MainWidget::usernameResolveDone(QPair msgIdAndStartToken, c // Always open bot chats, even from mention links. Ui::showPeerHistoryAsync(peer->id, ShowAtUnreadMsgId, Ui::ShowWay::Forward); } else { - Ui::showPeerProfile(peer); + _controller->showPeerInfo(peer); } } else { if (msgId == ShowAtProfileMsgId || !peer->isChannel()) { // show specific posts only in channels / supergroups @@ -4378,7 +4587,7 @@ void MainWidget::incrementSticker(DocumentData *sticker) { void MainWidget::activate() { if (_a_show.animating()) return; - if (!_wideSection && !_overview) { + if (!_mainSection && !_overview) { if (_hider) { if (_hider->wasOffered()) { _hider->setFocus(); @@ -4412,11 +4621,11 @@ bool MainWidget::isActive() const { } bool MainWidget::doWeReadServerHistory() const { - return isActive() && !_wideSection && !_overview && _history->doWeReadServerHistory(); + return isActive() && !_mainSection && !_overview && _history->doWeReadServerHistory(); } bool MainWidget::doWeReadMentions() const { - return isActive() && !_wideSection && !_overview && _history->doWeReadMentions(); + return isActive() && !_mainSection && !_overview && _history->doWeReadMentions(); } bool MainWidget::lastWasOnline() const { diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index c3b79b385..f9146036c 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -156,7 +156,8 @@ class MainWidget : public Ui::RpWidget, public RPCSender, private base::Subscrib public: MainWidget(QWidget *parent, not_null controller); - bool isSectionShown() const; + bool isMainSectionShown() const; + bool isThirdSectionShown() const; // Temporary methods, while top bar was not done inside HistoryWidget / OverviewWidget. bool paintTopBar(Painter &, int decreaseWidth, TimeMs ms); @@ -212,14 +213,17 @@ public: int backgroundFromY() const; PeerData *overviewPeer(); bool showMediaTypeSwitch() const; - void showWideSection(Window::SectionMemento &&memento); + void showSection( + Window::SectionMemento &&memento, + anim::type animated); + void updateColumnLayout(); void showMediaOverview(PeerData *peer, MediaOverviewType type, bool back = false, int32 lastScrollTop = -1); bool stackIsEmpty() const; void showBackFromStack(); void orderWidgets(); QRect historyRect() const; QPixmap grabForShowAnimation(const Window::SectionSlideParams ¶ms); - void checkWideSectionToLayer(); + void checkMainSectionToLayer(); void onSendFileConfirm(const FileLoadResultPtr &file); bool onSendSticker(DocumentData *sticker); @@ -442,8 +446,6 @@ public slots: void onUpdateMuted(); - void onStickersInstalled(uint64 setId); - void onViewsIncrement(); void ui_showPeerHistoryAsync(quint64 peerId, qint32 showAtMsgId, Ui::ShowWay way); @@ -523,12 +525,19 @@ private: mtpRequestId req); void mediaOverviewUpdated(const Notify::PeerUpdate &update); - Window::SectionSlideParams prepareShowAnimation(bool willHaveTopBarShadow, bool willHaveTabbedSection); - void showNewWideSection(Window::SectionMemento &&memento, bool back, bool saveInStack); - void dropWideSection(Window::SectionWidget *widget); + Window::SectionSlideParams prepareShowAnimation( + bool willHaveTopBarShadow); + void showNewSection( + Window::SectionMemento &&memento, + bool back, + bool saveInStack, + anim::type animated); + void dropMainSection(Window::SectionWidget *widget); + + Window::SectionSlideParams prepareThirdSectionAnimation(Window::SectionWidget *section); // All this methods use the prepareShowAnimation(). - Window::SectionSlideParams prepareWideSectionAnimation(Window::SectionWidget *section); + Window::SectionSlideParams prepareMainSectionAnimation(Window::SectionWidget *section); Window::SectionSlideParams prepareHistoryAnimation(PeerId historyPeerId); Window::SectionSlideParams prepareOverviewAnimation(); Window::SectionSlideParams prepareDialogsAnimation(); @@ -564,7 +573,8 @@ private: void inviteImportDone(const MTPUpdates &result); bool inviteImportFail(const RPCError &error); - int getSectionTop() const; + int getMainSectionTop() const; + int getThirdSectionTop() const; void hideAll(); void showAll(); @@ -581,11 +591,17 @@ private: Float *currentFloatPlayer() const { return _playerFloats.empty() ? nullptr : _playerFloats.back().get(); } - Window::AbstractSectionWidget *getFloatPlayerSection(not_null column) const; - void finishFloatPlayerDrag(not_null instance, bool closed); + Window::AbstractSectionWidget *getFloatPlayerSection( + Window::Column column) const; + void finishFloatPlayerDrag( + not_null instance, + bool closed); void updateFloatPlayerColumnCorner(QPoint center); QPoint getFloatPlayerPosition(not_null instance) const; - QPoint getFloatPlayerHiddenPosition(QPoint position, QSize size, RectPart side) const; + QPoint getFloatPlayerHiddenPosition( + QPoint position, + QSize size, + RectPart side) const; RectPart getFloatPlayerSide(QPoint center) const; bool ptsUpdateAndApply(int32 pts, int32 ptsCount, const MTPUpdates &updates); @@ -615,10 +631,11 @@ private: Animation _a_dialogsWidth; object_ptr _sideShadow; + object_ptr _thirdShadow = { nullptr }; object_ptr _sideResizeArea; object_ptr _dialogs; object_ptr _history; - object_ptr _wideSection = { nullptr }; + object_ptr _mainSection = { nullptr }; object_ptr _thirdSection = { nullptr }; object_ptr _overview = { nullptr }; diff --git a/Telegram/SourceFiles/mainwindow.cpp b/Telegram/SourceFiles/mainwindow.cpp index a40ffc56f..d0dd22850 100644 --- a/Telegram/SourceFiles/mainwindow.cpp +++ b/Telegram/SourceFiles/mainwindow.cpp @@ -812,7 +812,7 @@ void MainWindow::updateControlsGeometry() { if (_connecting) _connecting->moveToLeft(0, body.height() - _connecting->height()); if (_testingThemeWarning) _testingThemeWarning->setGeometry(body); - if (_main) _main->checkWideSectionToLayer(); + if (_main) _main->checkMainSectionToLayer(); } MainWindow::TempDirState MainWindow::tempDirState() { diff --git a/Telegram/SourceFiles/overviewwidget.cpp b/Telegram/SourceFiles/overviewwidget.cpp index 1e036afa5..637b223d4 100644 --- a/Telegram/SourceFiles/overviewwidget.cpp +++ b/Telegram/SourceFiles/overviewwidget.cpp @@ -62,7 +62,7 @@ OverviewInner::OverviewInner(OverviewWidget *overview, Ui::ScrollArea *scroll, P , _search(this, st::overviewFilter, langFactory(lng_dlg_filter)) , _cancelSearch(this, st::dialogsCancelSearch) , _itemsToBeLoaded(LinksOverviewPerPage * 2) -, _width(st::windowMinWidth) { +, _width(st::columnMinimalWidthMain) { subscribe(Auth().downloader().taskFinished(), [this] { update(); }); subscribe(Global::RefItemRemoved(), [this](HistoryItem *item) { itemRemoved(item); @@ -1314,7 +1314,7 @@ int32 OverviewInner::resizeToWidth(int32 nwidth, int32 scrollTop, int32 minHeigh contentLeftMin -= st::overviewFileLayout.songPadding.left(); contentLeftMax -= st::overviewFileLayout.songPadding.left(); } - auto widthWithMin = st::windowMinWidth; + auto widthWithMin = st::columnMinimalWidthMain; auto widthWithMax = st::overviewFileLayout.maxWidth + 2 * contentLeftMax; _rowsLeft = anim::interpolate(contentLeftMax, contentLeftMin, qMax(widthWithMax - _width, 0) / float64(widthWithMax - widthWithMin)); _rowWidth = qMin(_width - 2 * _rowsLeft, st::overviewFileLayout.maxWidth); @@ -2145,11 +2145,11 @@ int32 OverviewWidget::lastScrollTop() const { return _scroll->scrollTop(); } -bool OverviewWidget::wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn, Window::Column playerColumn) { +bool OverviewWidget::wheelEventFromFloatPlayer(QEvent *e) { return _scroll->viewportEvent(e); } -QRect OverviewWidget::rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const { +QRect OverviewWidget::rectForFloatPlayer() const { return mapToGlobal(_scroll->geometry()); } diff --git a/Telegram/SourceFiles/overviewwidget.h b/Telegram/SourceFiles/overviewwidget.h index c17515353..6fdc83912 100644 --- a/Telegram/SourceFiles/overviewwidget.h +++ b/Telegram/SourceFiles/overviewwidget.h @@ -349,8 +349,8 @@ public: void deleteSelectedItems(bool forEveryone); // Float player interface. - bool wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn, Window::Column playerColumn) override; - QRect rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const override; + bool wheelEventFromFloatPlayer(QEvent *e) override; + QRect rectForFloatPlayer() const override; void ui_repaintHistoryItem(not_null item); diff --git a/Telegram/SourceFiles/profile/profile_block_channel_members.cpp b/Telegram/SourceFiles/profile/profile_block_channel_members.cpp index 28d0914c3..957e1fea5 100644 --- a/Telegram/SourceFiles/profile/profile_block_channel_members.cpp +++ b/Telegram/SourceFiles/profile/profile_block_channel_members.cpp @@ -156,7 +156,7 @@ void ChannelMembersWidget::onAdmins() { void ChannelMembersWidget::onRecentActions() { if (auto channel = peer()->asChannel()) { if (auto main = App::main()) { - main->showWideSection(AdminLog::SectionMemento(channel)); + main->showSection(AdminLog::SectionMemento(channel), anim::type::normal); } } } diff --git a/Telegram/SourceFiles/profile/profile_block_settings.cpp b/Telegram/SourceFiles/profile/profile_block_settings.cpp index e12956725..72a0f7e1f 100644 --- a/Telegram/SourceFiles/profile/profile_block_settings.cpp +++ b/Telegram/SourceFiles/profile/profile_block_settings.cpp @@ -219,7 +219,7 @@ void SettingsWidget::onManageAdmins() { void SettingsWidget::onRecentActions() { if (auto channel = peer()->asChannel()) { if (auto main = App::main()) { - main->showWideSection(AdminLog::SectionMemento(channel)); + main->showSection(AdminLog::SectionMemento(channel), anim::type::normal); } } } diff --git a/Telegram/SourceFiles/profile/profile_block_shared_media.cpp b/Telegram/SourceFiles/profile/profile_block_shared_media.cpp index ba852b470..378990ff4 100644 --- a/Telegram/SourceFiles/profile/profile_block_shared_media.cpp +++ b/Telegram/SourceFiles/profile/profile_block_shared_media.cpp @@ -201,7 +201,7 @@ void SharedMediaWidget::onShowCommonGroups() { return; } if (auto main = App::main()) { - main->showWideSection(Profile::CommonGroups::SectionMemento(peer()->asUser())); + main->showSection(Profile::CommonGroups::SectionMemento(peer()->asUser()), anim::type::normal); } } diff --git a/Telegram/SourceFiles/profile/profile_common_groups_section.cpp b/Telegram/SourceFiles/profile/profile_common_groups_section.cpp index baeb70ab9..021cc2bc2 100644 --- a/Telegram/SourceFiles/profile/profile_common_groups_section.cpp +++ b/Telegram/SourceFiles/profile/profile_common_groups_section.cpp @@ -42,7 +42,11 @@ constexpr int kCommonGroupsPerPage = 40; } // namespace -object_ptr SectionMemento::createWidget(QWidget *parent, not_null controller, const QRect &geometry) { +object_ptr SectionMemento::createWidget( + QWidget *parent, + not_null controller, + Window::Column column, + const QRect &geometry) { auto result = object_ptr(parent, controller, _user); result->setInternalState(geometry, this); return std::move(result); @@ -196,7 +200,7 @@ int InnerWidget::resizeGetHeight(int newWidth) { auto contentLeftMin = st::profileCommonGroupsLeftMin; auto contentLeftMax = st::profileCommonGroupsLeftMax; - auto widthWithMin = st::windowMinWidth; + auto widthWithMin = st::columnMinimalWidthMain; auto widthWithMax = st::profileCommonGroupsWidthMax + 2 * contentLeftMax; _contentLeft = anim::interpolate(contentLeftMax, contentLeftMin, qMax(widthWithMax - newWidth, 0) / float64(widthWithMax - widthWithMin)); _contentWidth = qMin(newWidth - 2 * _contentLeft, st::profileCommonGroupsWidthMax); @@ -447,11 +451,11 @@ void Widget::showFinishedHook() { _fixedBar->setAnimatingMode(false); } -bool Widget::wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn, Window::Column playerColumn) { +bool Widget::wheelEventFromFloatPlayer(QEvent *e) { return _scroll->viewportEvent(e); } -QRect Widget::rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const { +QRect Widget::rectForFloatPlayer() 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 b81ceb0a0..0b76a60d0 100644 --- a/Telegram/SourceFiles/profile/profile_common_groups_section.h +++ b/Telegram/SourceFiles/profile/profile_common_groups_section.h @@ -43,7 +43,11 @@ public: SectionMemento(not_null user) : _user(user) { } - object_ptr createWidget(QWidget *parent, not_null controller, const QRect &geometry) override; + object_ptr createWidget( + QWidget *parent, + not_null controller, + Window::Column column, + const QRect &geometry) override; not_null getUser() const { return _user; @@ -189,8 +193,8 @@ public: void setInternalState(const QRect &geometry, not_null memento); // Float player interface. - bool wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn, Window::Column playerColumn) override; - QRect rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const override; + bool wheelEventFromFloatPlayer(QEvent *e) override; + QRect rectForFloatPlayer() const override; protected: void resizeEvent(QResizeEvent *e) override; diff --git a/Telegram/SourceFiles/profile/profile_cover.cpp b/Telegram/SourceFiles/profile/profile_cover.cpp index 00ca529fe..8dc839873 100644 --- a/Telegram/SourceFiles/profile/profile_cover.cpp +++ b/Telegram/SourceFiles/profile/profile_cover.cpp @@ -117,7 +117,7 @@ void CoverWidget::onCancelPhotoUpload() { int CoverWidget::countPhotoLeft(int newWidth) const { int result = st::profilePhotoLeftMin; - result += (newWidth - st::windowMinWidth) / 2; + result += (newWidth - st::columnMinimalWidthMain) / 2; return qMin(result, st::profilePhotoLeftMax); } diff --git a/Telegram/SourceFiles/profile/profile_inner_widget.cpp b/Telegram/SourceFiles/profile/profile_inner_widget.cpp index 1726e03f0..0827a815c 100644 --- a/Telegram/SourceFiles/profile/profile_inner_widget.cpp +++ b/Telegram/SourceFiles/profile/profile_inner_widget.cpp @@ -148,7 +148,7 @@ int InnerWidget::countBlocksHeight(RectPart countSide) const { int InnerWidget::countBlocksLeft(int newWidth) const { int result = st::profileBlockLeftMin; - result += (newWidth - st::windowMinWidth) / 2; + result += (newWidth - st::columnMinimalWidthMain) / 2; return qMin(result, st::profileBlockLeftMax); } diff --git a/Telegram/SourceFiles/profile/profile_section_memento.cpp b/Telegram/SourceFiles/profile/profile_section_memento.cpp index d6d53e558..ab35a8727 100644 --- a/Telegram/SourceFiles/profile/profile_section_memento.cpp +++ b/Telegram/SourceFiles/profile/profile_section_memento.cpp @@ -24,7 +24,11 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org namespace Profile { -object_ptr SectionMemento::createWidget(QWidget *parent, not_null controller, const QRect &geometry) { +object_ptr SectionMemento::createWidget( + QWidget *parent, + not_null controller, + Window::Column column, + const QRect &geometry) { auto result = object_ptr(parent, controller, _peer); result->setInternalState(geometry, this); return std::move(result); diff --git a/Telegram/SourceFiles/profile/profile_section_memento.h b/Telegram/SourceFiles/profile/profile_section_memento.h index ca6f44785..8cd006781 100644 --- a/Telegram/SourceFiles/profile/profile_section_memento.h +++ b/Telegram/SourceFiles/profile/profile_section_memento.h @@ -31,7 +31,11 @@ public: SectionMemento(PeerData *peer) : _peer(peer) { } - object_ptr createWidget(QWidget *parent, not_null controller, const QRect &geometry) override; + object_ptr createWidget( + QWidget *parent, + not_null controller, + Window::Column column, + const QRect &geometry) override; PeerData *getPeer() const { return _peer; diff --git a/Telegram/SourceFiles/profile/profile_widget.cpp b/Telegram/SourceFiles/profile/profile_widget.cpp index dc6324d32..8b84e2330 100644 --- a/Telegram/SourceFiles/profile/profile_widget.cpp +++ b/Telegram/SourceFiles/profile/profile_widget.cpp @@ -161,11 +161,11 @@ void Widget::showFinishedHook() { _inner->showFinished(); } -bool Widget::wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn, Window::Column playerColumn) { +bool Widget::wheelEventFromFloatPlayer(QEvent *e) { return _scroll->viewportEvent(e); } -QRect Widget::rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const { +QRect Widget::rectForFloatPlayer() const { return mapToGlobal(_scroll->geometry()); } diff --git a/Telegram/SourceFiles/profile/profile_widget.h b/Telegram/SourceFiles/profile/profile_widget.h index 062de6e82..bd513e8b7 100644 --- a/Telegram/SourceFiles/profile/profile_widget.h +++ b/Telegram/SourceFiles/profile/profile_widget.h @@ -55,8 +55,8 @@ public: void setInternalState(const QRect &geometry, not_null memento); // Float player interface. - bool wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn, Window::Column playerColumn) override; - QRect rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const override; + bool wheelEventFromFloatPlayer(QEvent *e) override; + QRect rectForFloatPlayer() const override; protected: void resizeEvent(QResizeEvent *e) override; diff --git a/Telegram/SourceFiles/ui/animation.h b/Telegram/SourceFiles/ui/animation.h index 3a5dcc734..41fe216cb 100644 --- a/Telegram/SourceFiles/ui/animation.h +++ b/Telegram/SourceFiles/ui/animation.h @@ -93,6 +93,11 @@ enum Notification { namespace anim { +enum class type { + normal, + instant, +}; + using transition = base::lambda; extern transition linear; diff --git a/Telegram/SourceFiles/ui/twidget.cpp b/Telegram/SourceFiles/ui/twidget.cpp index aaef88bb9..6ffb90c09 100644 --- a/Telegram/SourceFiles/ui/twidget.cpp +++ b/Telegram/SourceFiles/ui/twidget.cpp @@ -191,8 +191,6 @@ QPixmap myGrab(TWidget *target, QRect rect, QColor bg) { result.fill(bg); } - App::wnd()->widgetGrabbed().notify(true); - target->grabStart(); target->render(&result, QPoint(0, 0), rect, QWidget::DrawChildren | QWidget::IgnoreMask); target->grabFinish(); diff --git a/Telegram/SourceFiles/window/main_window.h b/Telegram/SourceFiles/window/main_window.h index eb959f111..a5cfcdc6e 100644 --- a/Telegram/SourceFiles/window/main_window.h +++ b/Telegram/SourceFiles/window/main_window.h @@ -92,9 +92,6 @@ public: base::Observable &dragFinished() { return _dragFinished; } - base::Observable &widgetGrabbed() { - return _widgetGrabbed; - } public slots: bool minimizeToTray(); @@ -184,8 +181,7 @@ private: base::Timer _inactivePressTimer; base::Observable _dragFinished; - base::Observable _widgetGrabbed; - + }; } // namespace Window diff --git a/Telegram/SourceFiles/window/section_memento.h b/Telegram/SourceFiles/window/section_memento.h index 68c1dab19..f1823eaa4 100644 --- a/Telegram/SourceFiles/window/section_memento.h +++ b/Telegram/SourceFiles/window/section_memento.h @@ -26,12 +26,14 @@ namespace Window { class Controller; class SectionWidget; +enum class Column; class SectionMemento { public: virtual object_ptr createWidget( QWidget *parent, not_null controller, + Column column, const QRect &geometry) = 0; virtual object_ptr createLayer( diff --git a/Telegram/SourceFiles/window/section_widget.cpp b/Telegram/SourceFiles/window/section_widget.cpp index ccee1bfe5..357792cab 100644 --- a/Telegram/SourceFiles/window/section_widget.cpp +++ b/Telegram/SourceFiles/window/section_widget.cpp @@ -21,6 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "window/section_widget.h" #include "application.h" +#include "window/section_memento.h" #include namespace Window { @@ -28,7 +29,7 @@ namespace Window { SectionWidget::SectionWidget( QWidget *parent, not_null controller) - : AbstractSectionWidget(parent, controller) { +: AbstractSectionWidget(parent, controller) { } void SectionWidget::setGeometryWithTopMoved( @@ -72,6 +73,10 @@ void SectionWidget::showAnimated( show(); } +std::unique_ptr SectionWidget::createMemento() { + return nullptr; +} + void SectionWidget::showFast() { show(); showFinished(); diff --git a/Telegram/SourceFiles/window/section_widget.h b/Telegram/SourceFiles/window/section_widget.h index a2442d6c5..b72ab4eac 100644 --- a/Telegram/SourceFiles/window/section_widget.h +++ b/Telegram/SourceFiles/window/section_widget.h @@ -45,10 +45,10 @@ public: } // Float player interface. - virtual bool wheelEventFromFloatPlayer(QEvent *e, Window::Column myColumn, Window::Column playerColumn) { + virtual bool wheelEventFromFloatPlayer(QEvent *e) { return false; } - virtual QRect rectForFloatPlayer(Window::Column myColumn, Window::Column playerColumn) const { + virtual QRect rectForFloatPlayer() const { return mapToGlobal(rect()); } @@ -67,7 +67,6 @@ class SectionMemento; struct SectionSlideParams { QPixmap oldContentCache; bool withTopBarShadow = false; - bool withTabbedSection = false; explicit operator bool() const { return !oldContentCache.isNull(); @@ -90,6 +89,9 @@ public: virtual bool hasTopBarShadow() const { return false; } + virtual bool forceAnimateBack() const { + return false; + } void showAnimated(SlideDirection direction, const SectionSlideParams ¶ms); void showFast(); @@ -109,7 +111,7 @@ public: // Create a memento of that section to store it in the history stack. // This method may modify the section ("take" heavy items). - virtual std::unique_ptr createMemento() = 0; + virtual std::unique_ptr createMemento(); void setInnerFocus() { doSetInnerFocus(); diff --git a/Telegram/SourceFiles/window/top_bar_widget.cpp b/Telegram/SourceFiles/window/top_bar_widget.cpp index 2a3863273..77e504773 100644 --- a/Telegram/SourceFiles/window/top_bar_widget.cpp +++ b/Telegram/SourceFiles/window/top_bar_widget.cpp @@ -23,9 +23,11 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "styles/style_window.h" #include "boxes/add_contact_box.h" #include "boxes/confirm_box.h" +#include "info/info_memento.h" #include "mainwidget.h" #include "mainwindow.h" #include "shortcuts.h" +#include "auth_session.h" #include "lang/lang_keys.h" #include "ui/special_buttons.h" #include "ui/widgets/buttons.h" @@ -36,8 +38,13 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "observer_peer.h" namespace Window { +namespace { -TopBarWidget::TopBarWidget(QWidget *parent, not_null controller) : TWidget(parent) +constexpr auto kThirdSectionInfoTimeoutMs = 1000; + +} // namespace + +TopBarWidget::TopBarWidget(QWidget *parent, not_null controller) : RpWidget(parent) , _controller(controller) , _clearSelection(this, langFactory(lng_selected_clear), st::topBarClearButton) , _forward(this, langFactory(lng_selected_forward), st::defaultActiveButton) @@ -46,6 +53,7 @@ TopBarWidget::TopBarWidget(QWidget *parent, not_null contro , _mediaType(this, langFactory(lng_media_type), st::topBarButton) , _call(this, st::topBarCall) , _search(this, st::topBarSearch) +, _infoToggle(this, st::topBarInfo) , _menuToggle(this, st::topBarMenuToggle) { subscribe(Lang::Current().updated(), [this] { refreshLang(); }); @@ -58,6 +66,7 @@ TopBarWidget::TopBarWidget(QWidget *parent, not_null contro _call->setClickedCallback([this] { onCall(); }); _search->setClickedCallback([this] { onSearch(); }); _menuToggle->setClickedCallback([this] { showMenu(); }); + _infoToggle->setClickedCallback([this] { toggleInfoSection(); }); subscribe(_controller->searchInPeerChanged(), [this](PeerData *peer) { _searchInPeer = peer; @@ -85,7 +94,12 @@ TopBarWidget::TopBarWidget(QWidget *parent, not_null contro updateControlsVisibility(); } })); - subscribe(Global::RefPhoneCallsEnabledChanged(), [this] { updateControlsVisibility(); }); + subscribe(Global::RefPhoneCallsEnabledChanged(), [this] { + updateControlsVisibility(); }); + + Auth().data().thirdSectionInfoEnabledValue() + | rpl::on_next([this](bool) { updateInfoToggleActive(); }) + | rpl::start(lifetime()); setCursor(style::cur_pointer); updateControlsVisibility(); @@ -109,7 +123,9 @@ void TopBarWidget::onClearSelection() { void TopBarWidget::onInfoClicked() { auto p = App::main() ? App::main()->historyPeer() : nullptr; - if (p) Ui::showPeerProfile(p); + if (p) { + _controller->showPeerInfo(p); + } } void TopBarWidget::onSearch() { @@ -163,6 +179,28 @@ void TopBarWidget::showMenu() { } } +void TopBarWidget::toggleInfoSection() { + if (Adaptive::ThreeColumn() + && Auth().data().thirdSectionInfoEnabled()) { + _controller->closeThirdSection(); + } else if (auto peer = App::main()->historyPeer()) { + if (_controller->canShowThirdSection()) { + Auth().data().setThirdSectionInfoEnabled(true); + Auth().saveDataDelayed(kThirdSectionInfoTimeoutMs); + if (Adaptive::ThreeColumn()) { + _controller->showSection(Info::Memento(peer->id)); + } else { + _controller->resizeForThirdSection(); + _controller->updateColumnLayout(); + } + } else { + _controller->showSection(Info::Memento(peer->id)); + } + } else { + updateControlsVisibility(); + } +} + bool TopBarWidget::eventFilter(QObject *obj, QEvent *e) { if (obj == _membersShowArea) { switch (e->type()) { @@ -288,10 +326,14 @@ void TopBarWidget::updateControlsGeometry() { _menuToggle->moveToRight(right, otherButtonsTop); _mediaType->moveToRight(right, otherButtonsTop); if (_info->isHidden()) { - right += _menuToggle->width(); + right += _menuToggle->width() + st::topBarSkip; } else { right += _info->width(); } + _infoToggle->moveToRight(right, otherButtonsTop); + if (!_infoToggle->isHidden()) { + right += _infoToggle->width() + st::topBarSkip; + } _search->moveToRight(right, otherButtonsTop); right += _search->width() + st::topBarCallSkip; _call->moveToRight(right, otherButtonsTop); @@ -322,6 +364,8 @@ void TopBarWidget::updateControlsVisibility() { _menuToggle->show(); } _search->show(); + _infoToggle->setVisible(!Adaptive::OneColumn() + && _controller->canShowThirdSection()); auto callsEnabled = false; if (auto user = historyPeer->asUser()) { callsEnabled = Global::PhoneCallsEnabled() && user->hasCalls(); @@ -421,6 +465,20 @@ void TopBarWidget::updateAdaptiveLayout() { rtlupdate(0, 0, st::titleUnreadCounterRight, st::titleUnreadCounterTop); }); } + updateInfoToggleActive(); +} + +void TopBarWidget::updateInfoToggleActive() { + auto infoThirdActive = Adaptive::ThreeColumn() + && Auth().data().thirdSectionInfoEnabled(); + auto iconOverride = infoThirdActive + ? &st::topBarInfoActive + : nullptr; + auto ripplOverride = infoThirdActive + ? &st::lightButtonBgOver + : nullptr; + _infoToggle->setIconOverride(iconOverride, iconOverride); + _infoToggle->setRippleColorOverride(ripplOverride); } Ui::RoundButton *TopBarWidget::mediaTypeButton() { diff --git a/Telegram/SourceFiles/window/top_bar_widget.h b/Telegram/SourceFiles/window/top_bar_widget.h index 5f0d64ac6..07a0ebb42 100644 --- a/Telegram/SourceFiles/window/top_bar_widget.h +++ b/Telegram/SourceFiles/window/top_bar_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" namespace Ui { class PeerAvatarButton; @@ -33,7 +33,7 @@ namespace Window { class Controller; -class TopBarWidget : public TWidget, private base::Subscriber { +class TopBarWidget : public Ui::RpWidget, private base::Subscriber { Q_OBJECT public: @@ -68,6 +68,7 @@ private: void refreshLang(); void updateControlsGeometry(); void selectedShowCallback(); + void updateInfoToggleActive(); void onForwardSelection(); void onDeleteSelection(); @@ -76,6 +77,7 @@ private: void onCall(); void onSearch(); void showMenu(); + void toggleInfoSection(); void updateAdaptiveLayout(); int countSelectedButtonsTop(float64 selectedShown); @@ -97,6 +99,7 @@ private: object_ptr _call; object_ptr _search; + object_ptr _infoToggle; object_ptr _menuToggle; object_ptr _menu = { nullptr }; diff --git a/Telegram/SourceFiles/window/window.style b/Telegram/SourceFiles/window/window.style index 1b89cfc76..ad3534d41 100644 --- a/Telegram/SourceFiles/window/window.style +++ b/Telegram/SourceFiles/window/window.style @@ -30,6 +30,10 @@ windowDefaultHeight: 600px; windowShadow: icon {{ "window_shadow", windowShadowFg }}; windowShadowShift: 1px; +columnMinimalWidthLeft: 260px; +columnMinimalWidthMain: 380px; +columnMinimalWidthThird: 345px; + adaptiveChatWideWidth: 880px; notifyBorder: windowShadowFgFallback; @@ -257,9 +261,9 @@ topBarSearch: IconButton { width: 40px; height: topBarHeight; - icon: icon {{ "title_search-flip_horizontal", menuIconFg }}; - iconOver: icon {{ "title_search-flip_horizontal", menuIconFgOver }}; - iconPosition: point(11px, 19px); + icon: icon {{ "top_bar_search", menuIconFg }}; + iconOver: icon {{ "top_bar_search", menuIconFgOver }}; + iconPosition: point(4px, 11px); rippleAreaPosition: point(0px, 7px); rippleAreaSize: 40px; @@ -268,10 +272,16 @@ topBarSearch: IconButton { } } topBarCall: IconButton(topBarSearch) { - icon: icon {{ "add_contact_phone", menuIconFg }}; - iconOver: icon {{ "add_contact_phone", menuIconFgOver }}; + icon: icon {{ "top_bar_call", menuIconFg }}; + iconOver: icon {{ "top_bar_call", menuIconFgOver }}; } -topBarCallSkip: 4px; +topBarInfo: IconButton(topBarSearch) { + icon: icon {{ "top_bar_profile", menuIconFg }}; + iconOver: icon {{ "top_bar_profile", menuIconFgOver }}; +} +topBarInfoActive: icon {{ "top_bar_profile", windowBgActive }}; +topBarSkip: -2px; +topBarCallSkip: -1px; topBarMenuToggle: IconButton(topBarSearch) { width: 44px; diff --git a/Telegram/SourceFiles/window/window_controller.cpp b/Telegram/SourceFiles/window/window_controller.cpp index 8becd0e31..f4a0b0b31 100644 --- a/Telegram/SourceFiles/window/window_controller.cpp +++ b/Telegram/SourceFiles/window/window_controller.cpp @@ -21,6 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "window/window_controller.h" #include "window/main_window.h" +#include "info/info_memento.h" #include "mainwidget.h" #include "mainwindow.h" #include "styles/style_window.h" @@ -30,6 +31,11 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "apiwrap.h" namespace Window { +namespace { + +constexpr auto kThirdSectionInfoTimeoutMs = 1000; + +} // namespace void Controller::enableGifPauseReason(GifPauseReason reason) { if (!(_gifPauseReasons & reason)) { @@ -61,21 +67,29 @@ int Controller::dialogsSmallColumnWidth() const { return st::dialogsPadding.x() + st::dialogsPhotoSize + st::dialogsPadding.x(); } +int Controller::minimalThreeColumnWidth() const { + return st::columnMinimalWidthLeft + + st::columnMinimalWidthMain + + st::columnMinimalWidthThird; +} + Controller::ColumnLayout Controller::computeColumnLayout() const { auto layout = Adaptive::WindowLayout::OneColumn; auto bodyWidth = window()->bodyWidget()->width(); auto dialogsWidth = qRound(bodyWidth * dialogsWidthRatio().value()); auto chatWidth = bodyWidth - dialogsWidth; - accumulate_max(chatWidth, st::windowMinWidth); + auto thirdWidth = 0; + accumulate_max(chatWidth, st::columnMinimalWidthMain); dialogsWidth = bodyWidth - chatWidth; auto useOneColumnLayout = [this, bodyWidth, dialogsWidth] { - auto someSectionShown = !App::main()->selectingPeer() && App::main()->isSectionShown(); - if (dialogsWidth < st::dialogsPadding.x() && (Adaptive::OneColumn() || someSectionShown)) { + if (dialogsWidth < st::dialogsPadding.x() && Adaptive::OneColumn()) { return true; } - if (bodyWidth < st::windowMinWidth + st::dialogsWidthMin) { + auto minimalNormal = st::columnMinimalWidthLeft + + st::columnMinimalWidthMain; + if (bodyWidth < minimalNormal) { return true; } return false; @@ -89,6 +103,18 @@ Controller::ColumnLayout Controller::computeColumnLayout() const { return false; }; + auto useNormalLayout = [this, bodyWidth] { + // Used if useSmallColumnLayout() == false. + if (bodyWidth < minimalThreeColumnWidth()) { + return true; + } + if (!Auth().data().tabbedSelectorSectionEnabled() + && !Auth().data().thirdSectionInfoEnabled()) { + return true; + } + return false; + }; + if (useOneColumnLayout()) { dialogsWidth = chatWidth = bodyWidth; } else if (useSmallColumnLayout()) { @@ -99,7 +125,7 @@ Controller::ColumnLayout Controller::computeColumnLayout() const { } else if (dialogsListFocused().value()) { return true; } - return !App::main()->isSectionShown(); + return !App::main()->isMainSectionShown(); }; if (forceWideDialogs()) { dialogsWidth = st::dialogsWidthMin; @@ -107,33 +133,81 @@ Controller::ColumnLayout Controller::computeColumnLayout() const { dialogsWidth = dialogsSmallColumnWidth(); } chatWidth = bodyWidth - dialogsWidth; - } else { + } else if (useNormalLayout()) { layout = Adaptive::WindowLayout::Normal; - accumulate_max(dialogsWidth, st::dialogsWidthMin); + accumulate_max(dialogsWidth, st::columnMinimalWidthLeft); chatWidth = bodyWidth - dialogsWidth; + } else { + layout = Adaptive::WindowLayout::ThreeColumn; + accumulate_max(dialogsWidth, st::columnMinimalWidthLeft); + thirdWidth = st::columnMinimalWidthThird; + accumulate_min( + dialogsWidth, + bodyWidth - thirdWidth - st::columnMinimalWidthMain); + chatWidth = bodyWidth - dialogsWidth - thirdWidth; } - return { bodyWidth, dialogsWidth, chatWidth, layout }; + return { bodyWidth, dialogsWidth, chatWidth, thirdWidth, layout }; } -bool Controller::canProvideChatWidth(int requestedWidth) const { +bool Controller::canShowThirdSection() const { auto currentLayout = computeColumnLayout(); - auto extendBy = requestedWidth - currentLayout.chatWidth; + auto extendBy = minimalThreeColumnWidth() + - currentLayout.bodyWidth; if (extendBy <= 0) { return true; } return window()->canExtendWidthBy(extendBy); } -void Controller::provideChatWidth(int requestedWidth) { - auto currentLayout = computeColumnLayout(); - auto extendBy = requestedWidth - currentLayout.chatWidth; - if (extendBy <= 0) { +void Controller::resizeForThirdSection() { + auto layout = computeColumnLayout(); + if (layout.windowLayout == Adaptive::WindowLayout::ThreeColumn) { return; } + + auto tabbedSelectorSectionEnabled = + Auth().data().tabbedSelectorSectionEnabled(); + auto thirdSectionInfoEnabled = + Auth().data().thirdSectionInfoEnabled(); + Auth().data().setTabbedSelectorSectionEnabled(false); + Auth().data().setThirdSectionInfoEnabled(false); + + auto extendBy = st::columnMinimalWidthThird; + auto newBodyWidth = layout.bodyWidth + extendBy; + dialogsWidthRatio().set( + float64(layout.dialogsWidth) / newBodyWidth, + true); window()->tryToExtendWidthBy(extendBy); - auto newLayout = computeColumnLayout(); - if (newLayout.windowLayout != Adaptive::WindowLayout::OneColumn) { - dialogsWidthRatio().set(float64(newLayout.bodyWidth - requestedWidth) / newLayout.bodyWidth, true); + + Auth().data().setTabbedSelectorSectionEnabled( + tabbedSelectorSectionEnabled); + Auth().data().setThirdSectionInfoEnabled( + thirdSectionInfoEnabled); +} + +void Controller::closeThirdSection() { + auto newWindowSize = window()->size(); + auto layout = computeColumnLayout(); + if (layout.windowLayout == Adaptive::WindowLayout::ThreeColumn) { + auto noResize = window()->isFullScreen() + || window()->isMaximized(); + auto newBodyWidth = noResize + ? layout.bodyWidth + : (layout.bodyWidth - layout.thirdWidth); + dialogsWidthRatio().set( + float64(layout.dialogsWidth) / newBodyWidth, + true); + newWindowSize = QSize( + window()->width() + (newBodyWidth - layout.bodyWidth), + window()->height()); + } + Auth().data().setTabbedSelectorSectionEnabled(false); + Auth().data().setThirdSectionInfoEnabled(false); + Auth().saveDataDelayed(kThirdSectionInfoTimeoutMs); + if (window()->size() != newWindowSize) { + window()->resize(newWindowSize); + } else { + updateColumnLayout(); } } @@ -184,15 +258,57 @@ void Controller::showJumpToDate(not_null peer, QDate requestedDate) { Ui::show(std::move(box)); } +void Controller::updateColumnLayout() { + App::main()->updateColumnLayout(); +} + +void Controller::showPeerHistory( + PeerId peerId, + Ui::ShowWay way, + MsgId msgId) { + Ui::showPeerHistory(peerId, msgId, way); +} + void Controller::showPeerHistory( not_null peer, Ui::ShowWay way, MsgId msgId) { - Ui::showPeerHistory(peer, msgId, way); + showPeerHistory(peer->id, way, msgId); } -void Controller::showWideSection(SectionMemento &&memento) { - App::main()->showWideSection(std::move(memento)); +void Controller::showPeerHistory( + not_null history, + Ui::ShowWay way, + MsgId msgId) { + showPeerHistory(history->peer->id, way, msgId); +} + +void Controller::showPeerInfo( + PeerId peerId, + anim::type animated) { + if (Adaptive::ThreeColumn()) { + Auth().data().setThirdSectionInfoEnabled(true); + Auth().saveDataDelayed(kThirdSectionInfoTimeoutMs); + } + showSection(Info::Memento(peerId), animated); +} + +void Controller::showPeerInfo( + not_null peer, + anim::type animated) { + showPeerInfo(peer->id, animated); +} + +void Controller::showPeerInfo( + not_null history, + anim::type animated) { + showPeerInfo(history->peer->id, animated); +} + +void Controller::showSection( + SectionMemento &&memento, + anim::type animated) { + App::main()->showSection(std::move(memento), animated); } void Controller::showBackFromStack() { diff --git a/Telegram/SourceFiles/window/window_controller.h b/Telegram/SourceFiles/window/window_controller.h index 6721bdc79..05053a3dd 100644 --- a/Telegram/SourceFiles/window/window_controller.h +++ b/Telegram/SourceFiles/window/window_controller.h @@ -78,12 +78,47 @@ public: int bodyWidth; int dialogsWidth; int chatWidth; + int thirdWidth; Adaptive::WindowLayout windowLayout; }; ColumnLayout computeColumnLayout() const; int dialogsSmallColumnWidth() const; - bool canProvideChatWidth(int requestedWidth) const; - void provideChatWidth(int requestedWidth); + void updateColumnLayout(); + bool canShowThirdSection() const; + void resizeForThirdSection(); + void closeThirdSection(); + void showSection( + SectionMemento &&memento, + anim::type animated = anim::type::normal); + void showBackFromStack(); + void showSpecialLayer( + object_ptr &&layer, + LayerOptions options = LayerOption::Animated); + void hideSpecialLayer( + LayerOptions options = LayerOption::Animated); + + void showPeerHistory( + PeerId peerId, + Ui::ShowWay way = Ui::ShowWay::ClearStack, + MsgId msgId = ShowAtUnreadMsgId); + void showPeerHistory( + not_null peer, + Ui::ShowWay way = Ui::ShowWay::ClearStack, + MsgId msgId = ShowAtUnreadMsgId); + void showPeerHistory( + not_null history, + Ui::ShowWay way = Ui::ShowWay::ClearStack, + MsgId msgId = ShowAtUnreadMsgId); + + void showPeerInfo( + PeerId peerId, + anim::type animated = anim::type::normal); + void showPeerInfo( + not_null peer, + anim::type animated = anim::type::normal); + void showPeerInfo( + not_null history, + anim::type animated = anim::type::normal); void showJumpToDate(not_null peer, QDate requestedDate); @@ -106,19 +141,8 @@ public: return _dialogsListDisplayForced; } - void showPeerHistory( - not_null peer, - Ui::ShowWay way = Ui::ShowWay::ClearStack, - MsgId msgId = ShowAtUnreadMsgId); - void showWideSection(SectionMemento &&memento); - void showBackFromStack(); - void showSpecialLayer( - object_ptr &&layer, - LayerOptions options = LayerOption::Animated); - void hideSpecialLayer( - LayerOptions options = LayerOption::Animated); - private: + int minimalThreeColumnWidth() const; not_null chats() const; not_null _window;