diff --git a/Telegram/SourceFiles/boxes/edit_caption_box.cpp b/Telegram/SourceFiles/boxes/edit_caption_box.cpp index 1b6b574814..6eda94b491 100644 --- a/Telegram/SourceFiles/boxes/edit_caption_box.cpp +++ b/Telegram/SourceFiles/boxes/edit_caption_box.cpp @@ -711,7 +711,7 @@ void EditCaptionBox::setupEmojiPanel() { st::emojiPanMinHeight / 2, st::emojiPanMinHeight); _emojiPanel->hide(); - _emojiPanel->getSelector()->emojiChosen( + _emojiPanel->selector()->emojiChosen( ) | rpl::start_with_next([=](EmojiPtr emoji) { Ui::InsertEmojiAtCursor(_field->textCursor(), emoji); }, lifetime()); diff --git a/Telegram/SourceFiles/boxes/send_files_box.cpp b/Telegram/SourceFiles/boxes/send_files_box.cpp index c2e88250e6..1e237ee6cf 100644 --- a/Telegram/SourceFiles/boxes/send_files_box.cpp +++ b/Telegram/SourceFiles/boxes/send_files_box.cpp @@ -1688,7 +1688,7 @@ void SendFilesBox::setupEmojiPanel() { st::emojiPanMinHeight / 2, st::emojiPanMinHeight); _emojiPanel->hide(); - _emojiPanel->getSelector()->emojiChosen( + _emojiPanel->selector()->emojiChosen( ) | rpl::start_with_next([=](EmojiPtr emoji) { Ui::InsertEmojiAtCursor(_caption->textCursor(), emoji); }, lifetime()); diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp index 54615465a6..096c5a9702 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp @@ -1574,6 +1574,8 @@ int StickersListWidget::megagroupSetInfoLeft() const { } void StickersListWidget::paintMegagroupEmptySet(Painter &p, int y, bool buttonSelected) { + p.setPen(st::emojiPanHeaderFg); + auto infoLeft = megagroupSetInfoLeft(); _megagroupSetAbout.drawLeft(p, infoLeft, y, width() - infoLeft, width()); diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp b/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp index 5a70f2c12c..0e650a7dd3 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp +++ b/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp @@ -26,20 +26,27 @@ constexpr auto kDelayedHideTimeoutMs = 3000; TabbedPanel::TabbedPanel( QWidget *parent, - not_null controller) -: TabbedPanel( - parent, - controller, - object_ptr(nullptr, controller)) { + not_null controller, + not_null selector) +: TabbedPanel(parent, controller, { nullptr }, selector) { } TabbedPanel::TabbedPanel( QWidget *parent, not_null controller, object_ptr selector) +: TabbedPanel(parent, controller, std::move(selector), nullptr) { +} + +TabbedPanel::TabbedPanel( + QWidget *parent, + not_null controller, + object_ptr ownedSelector, + TabbedSelector *nonOwnedSelector) : RpWidget(parent) , _controller(controller) -, _selector(std::move(selector)) +, _ownedSelector(std::move(ownedSelector)) +, _selector(nonOwnedSelector ? nonOwnedSelector : _ownedSelector.data()) , _heightRatio(st::emojiPanHeightRatio) , _minContentHeight(st::emojiPanMinHeight) , _maxContentHeight(st::emojiPanMaxHeight) { @@ -106,6 +113,14 @@ TabbedPanel::TabbedPanel( hide(); } +not_null TabbedPanel::selector() const { + return _selector; +} + +bool TabbedPanel::isSelectorStolen() const { + return (_selector->parent() != this); +} + void TabbedPanel::moveBottomRight(int bottom, int right) { const auto isNew = (_bottom != bottom || _right != right); _bottom = bottom; @@ -366,17 +381,6 @@ void TabbedPanel::toggleAnimated() { } } -object_ptr TabbedPanel::takeSelector() { - if (!isHidden() && !_hiding) { - startOpacityAnimation(true); - } - return std::move(_selector); -} - -QPointer TabbedPanel::getSelector() const { - return _selector.data(); -} - void TabbedPanel::hideFinished() { hide(); _a_show.stop(); @@ -450,6 +454,10 @@ bool TabbedPanel::overlaps(const QRect &globalRect) const { || inner.marginsRemoved(QMargins(0, st::buttonRadius, 0, st::buttonRadius)).contains(testRect); } -TabbedPanel::~TabbedPanel() = default; +TabbedPanel::~TabbedPanel() { + if (!_ownedSelector) { + _controller->takeTabbedSelectorOwnershipFrom(this); + } +} } // namespace ChatHelpers diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_panel.h b/Telegram/SourceFiles/chat_helpers/tabbed_panel.h index 677bf68368..bc6782865d 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_panel.h +++ b/Telegram/SourceFiles/chat_helpers/tabbed_panel.h @@ -27,14 +27,16 @@ class TabbedPanel : public Ui::RpWidget { public: TabbedPanel( QWidget *parent, - not_null controller); + not_null controller, + not_null selector); TabbedPanel( QWidget *parent, not_null controller, object_ptr selector); - object_ptr takeSelector(); - QPointer getSelector() const; + [[nodiscard]] bool isSelectorStolen() const; + [[nodiscard]] not_null selector() const; + void moveBottomRight(int bottom, int right); void setDesiredHeightValues( float64 ratio, @@ -64,6 +66,12 @@ protected: bool eventFilter(QObject *obj, QEvent *e) override; private: + TabbedPanel( + QWidget *parent, + not_null controller, + object_ptr ownedSelector, + TabbedSelector *nonOwnedSelector); + void hideByTimerOrLeave(); void moveByBottom(); bool isDestroying() const { @@ -89,8 +97,9 @@ private: bool preventAutoHide() const; void updateContentHeight(); - not_null _controller; - object_ptr _selector; + const not_null _controller; + const object_ptr _ownedSelector = { nullptr }; + const not_null _selector; int _contentMaxHeight = 0; int _contentHeight = 0; diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_section.cpp b/Telegram/SourceFiles/chat_helpers/tabbed_section.cpp index a3c659554f..990ccbd780 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_section.cpp +++ b/Telegram/SourceFiles/chat_helpers/tabbed_section.cpp @@ -7,56 +7,27 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "chat_helpers/tabbed_section.h" -#include "styles/style_chat_helpers.h" #include "chat_helpers/tabbed_selector.h" +#include "window/window_session_controller.h" +#include "styles/style_chat_helpers.h" namespace ChatHelpers { -TabbedMemento::TabbedMemento( - object_ptr selector, - Fn)> returnMethod) -: _selector(std::move(selector)) -, _returnMethod(std::move(returnMethod)) { -} - object_ptr TabbedMemento::createWidget( QWidget *parent, not_null controller, Window::Column column, const QRect &geometry) { - auto result = object_ptr( - parent, - controller, - std::move(_selector), - std::move(_returnMethod)); + auto result = object_ptr(parent, controller); result->setGeometry(geometry); return std::move(result); } -TabbedMemento::~TabbedMemento() { - if (_returnMethod && _selector) { - _returnMethod(std::move(_selector)); - } -} - TabbedSection::TabbedSection( QWidget *parent, not_null controller) -: TabbedSection( - parent, - controller, - object_ptr(this, controller), - Fn)>()) { -} - -TabbedSection::TabbedSection( - QWidget *parent, - not_null controller, - object_ptr selector, - Fn)> returnMethod) : Window::SectionWidget(parent, controller) -, _selector(std::move(selector)) -, _returnMethod(std::move(returnMethod)) { +, _selector(controller->tabbedSelector()) { _selector->setParent(this); _selector->setRoundRadius(0); _selector->setGeometry(rect()); @@ -80,14 +51,6 @@ void TabbedSection::resizeEvent(QResizeEvent *e) { _selector->setGeometry(rect()); } -object_ptr TabbedSection::takeSelector() { - _selector->beforeHiding(); - return std::move(_selector); -} - -QPointer TabbedSection::getSelector() const { - return _selector.data(); -} bool TabbedSection::showInternal( not_null memento, const Window::SectionShow ¶ms) { @@ -104,9 +67,7 @@ QRect TabbedSection::rectForFloatPlayer() const { TabbedSection::~TabbedSection() { beforeHiding(); - if (_returnMethod) { - _returnMethod(takeSelector()); - } + controller()->takeTabbedSelectorOwnershipFrom(this); } } // namespace ChatHelpers diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_section.h b/Telegram/SourceFiles/chat_helpers/tabbed_section.h index a7b84a28a9..2004969070 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_section.h +++ b/Telegram/SourceFiles/chat_helpers/tabbed_section.h @@ -16,9 +16,7 @@ class TabbedSelector; class TabbedMemento : public Window::SectionMemento { public: - TabbedMemento( - object_ptr selector, - Fn)> returnMethod); + TabbedMemento() = default; TabbedMemento(TabbedMemento &&other) = default; TabbedMemento &operator=(TabbedMemento &&other) = default; @@ -28,12 +26,6 @@ public: Window::Column column, const QRect &geometry) override; - ~TabbedMemento(); - -private: - object_ptr _selector; - Fn)> _returnMethod; - }; class TabbedSection : public Window::SectionWidget { @@ -41,18 +33,10 @@ public: TabbedSection( QWidget *parent, not_null controller); - TabbedSection( - QWidget *parent, - not_null controller, - object_ptr selector, - Fn)> returnMethod); void beforeHiding(); void afterShown(); - object_ptr takeSelector(); - QPointer getSelector() const; - bool showInternal( not_null memento, const Window::SectionShow ¶ms) override; @@ -73,8 +57,7 @@ protected: } private: - object_ptr _selector; - Fn)> _returnMethod; + const not_null _selector; }; diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp b/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp index b6c378213c..9f01b36f90 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp +++ b/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp @@ -11,7 +11,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "chat_helpers/stickers_list_widget.h" #include "chat_helpers/gifs_list_widget.h" #include "chat_helpers/stickers.h" -#include "styles/style_chat_helpers.h" #include "ui/widgets/buttons.h" #include "ui/widgets/labels.h" #include "ui/widgets/shadow.h" @@ -21,10 +20,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/window_session_controller.h" #include "storage/localstorage.h" #include "data/data_channel.h" +#include "data/data_session.h" #include "lang/lang_keys.h" #include "mainwindow.h" #include "observer_peer.h" #include "apiwrap.h" +#include "styles/style_chat_helpers.h" namespace ChatHelpers { @@ -291,8 +292,8 @@ TabbedSelector::TabbedSelector( createTab(SelectorTab::Gifs), } } , _currentTabType(full() - ? session().settings().selectorTab() - : SelectorTab::Emoji) { + ? session().settings().selectorTab() + : SelectorTab::Emoji) { resize(st::emojiPanWidth, st::emojiPanMaxHeight); for (auto &tab : _tabs) { @@ -364,10 +365,16 @@ TabbedSelector::TabbedSelector( stickers()->showStickerSet(setId); _showRequests.fire({}); }, lifetime()); + + session().data().stickersUpdated( + ) | rpl::start_with_next([=] { + refreshStickers(); + }, lifetime()); } //setAttribute(Qt::WA_AcceptTouchEvents); setAttribute(Qt::WA_OpaquePaintEvent, false); showAll(); + hide(); } TabbedSelector::~TabbedSelector() = default; @@ -651,13 +658,6 @@ void TabbedSelector::afterShown() { } } -void TabbedSelector::showMegagroupSet(ChannelData *megagroup) { - if (!full()) { - return; - } - stickers()->showMegagroupSet(megagroup); -} - void TabbedSelector::setCurrentPeer(PeerData *peer) { if (!full()) { return; @@ -665,6 +665,7 @@ void TabbedSelector::setCurrentPeer(PeerData *peer) { gifs()->setInlineQueryPeer(peer); _currentPeer = peer; checkRestrictedPeer(); + stickers()->showMegagroupSet(peer ? peer->asMegagroup() : nullptr); } void TabbedSelector::checkRestrictedPeer() { diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_selector.h b/Telegram/SourceFiles/chat_helpers/tabbed_selector.h index 3ed8d2ed3c..2d29dae6f9 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_selector.h +++ b/Telegram/SourceFiles/chat_helpers/tabbed_selector.h @@ -70,7 +70,6 @@ public: void setRoundRadius(int radius); void refreshStickers(); - void showMegagroupSet(ChannelData *megagroup); void setCurrentPeer(PeerData *peer); void hideFinished(); diff --git a/Telegram/SourceFiles/core/event_filter.cpp b/Telegram/SourceFiles/core/event_filter.cpp index 9d97ba30a1..63422f26c3 100644 --- a/Telegram/SourceFiles/core/event_filter.cpp +++ b/Telegram/SourceFiles/core/event_filter.cpp @@ -11,10 +11,11 @@ namespace Core { EventFilter::EventFilter( not_null parent, + not_null object, Fn)> filter) : QObject(parent) , _filter(std::move(filter)) { - parent->installEventFilter(this); + object->installEventFilter(this); } bool EventFilter::eventFilter(QObject *watched, QEvent *event) { @@ -24,7 +25,14 @@ bool EventFilter::eventFilter(QObject *watched, QEvent *event) { not_null InstallEventFilter( not_null object, Fn)> filter) { - return new EventFilter(object, std::move(filter)); + return InstallEventFilter(object, object, std::move(filter)); +} + +not_null InstallEventFilter( + not_null context, + not_null object, + Fn)> filter) { + return new EventFilter(context, object, std::move(filter)); } } // namespace Core diff --git a/Telegram/SourceFiles/core/event_filter.h b/Telegram/SourceFiles/core/event_filter.h index f11d686f09..c7d573f46d 100644 --- a/Telegram/SourceFiles/core/event_filter.h +++ b/Telegram/SourceFiles/core/event_filter.h @@ -13,6 +13,7 @@ class EventFilter : public QObject { public: EventFilter( not_null parent, + not_null object, Fn)> filter); protected: @@ -27,4 +28,9 @@ not_null InstallEventFilter( not_null object, Fn)> filter); +not_null InstallEventFilter( + not_null context, + not_null object, + Fn)> filter); + } // namespace Core diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index b085b91bf3..6fd266f0d9 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/share_box.h" #include "boxes/edit_caption_box.h" #include "core/file_utilities.h" +#include "core/event_filter.h" #include "ui/toast/toast.h" #include "ui/special_buttons.h" #include "ui/emoji_config.h" @@ -130,12 +131,6 @@ void ActivateWindow(not_null controller) { Core::App().activateWindowDelayed(window); } -void InsertEmojiToField(not_null field, EmojiPtr emoji) { - if (!field->isHidden()) { - Ui::InsertEmojiAtCursor(field->textCursor(), emoji); - } -} - bool ShowHistoryEndInsteadOfUnread( not_null session, PeerId peerId) { @@ -292,8 +287,6 @@ HistoryWidget::HistoryWidget( return recordingAnimationCallback(now); }) , _kbScroll(this, st::botKbScroll) -, _tabbedPanel(this, controller) -, _tabbedSelector(_tabbedPanel->getSelector()) , _attachDragState(DragState::None) , _attachDragDocument(this) , _attachDragPhoto(this) @@ -434,11 +427,6 @@ HistoryWidget::HistoryWidget( _botKeyboardHide->hide(); _botCommandStart->hide(); - _tabbedSelectorToggle->installEventFilter(_tabbedPanel); - _tabbedSelectorToggle->addClickHandler([=] { - toggleTabbedSelectorMode(); - }); - _botKeyboardShow->addClickHandler([=] { toggleKeyboard(); }); _botKeyboardHide->addClickHandler([=] { toggleKeyboard(); }); _botCommandStart->addClickHandler([=] { startBotCommand(); }); @@ -658,24 +646,55 @@ HistoryWidget::HistoryWidget( setupShortcuts(); } +void HistoryWidget::refreshTabbedPanel() { + if (_peer && controller()->hasTabbedSelectorOwnership()) { + createTabbedPanel(); + } else { + setTabbedPanel(nullptr); + } +} + void HistoryWidget::initTabbedSelector() { - _tabbedSelector->emojiChosen( - ) | rpl::start_with_next([=](EmojiPtr emoji) { - InsertEmojiToField(_field, emoji); + refreshTabbedPanel(); + + _tabbedSelectorToggle->addClickHandler([=] { + toggleTabbedSelectorMode(); + }); + + const auto selector = controller()->tabbedSelector(); + + Core::InstallEventFilter(this, selector, [=](not_null e) { + if (_tabbedPanel && e->type() == QEvent::ParentChange) { + setTabbedPanel(nullptr); + } + return false; + }); + + selector->emojiChosen( + ) | rpl::filter([=] { + return !isHidden() && !_field->isHidden(); + }) | rpl::start_with_next([=](EmojiPtr emoji) { + Ui::InsertEmojiAtCursor(_field->textCursor(), emoji); }, lifetime()); - _tabbedSelector->fileChosen( - ) | rpl::start_with_next([=](not_null document) { + selector->fileChosen( + ) | rpl::filter([=] { + return !isHidden(); + }) | rpl::start_with_next([=](not_null document) { sendExistingDocument(document); }, lifetime()); - _tabbedSelector->photoChosen( - ) | rpl::start_with_next([=](not_null photo) { + selector->photoChosen( + ) | rpl::filter([=] { + return !isHidden(); + }) | rpl::start_with_next([=](not_null photo) { sendExistingPhoto(photo); }, lifetime()); - _tabbedSelector->inlineResultChosen( - ) | rpl::start_with_next([=](TabbedSelector::InlineChosen data) { + selector->inlineResultChosen( + ) | rpl::filter([=] { + return !isHidden(); + }) | rpl::start_with_next([=](TabbedSelector::InlineChosen data) { sendInlineResult(data.result, data.bot); }, lifetime()); } @@ -952,11 +971,9 @@ int HistoryWidget::itemTopForHighlight( void HistoryWidget::start() { session().data().stickersUpdated( - ) | rpl::start_with_next([this] { - _tabbedSelector->refreshStickers(); + ) | rpl::start_with_next([=] { updateStickersByEmoji(); }, lifetime()); - updateRecentStickers(); session().data().notifySavedGifsUpdated(); subscribe(session().api().fullPeerUpdated(), [this](PeerData *peer) { fullPeerUpdated(peer); @@ -1072,9 +1089,6 @@ void HistoryWidget::orderWidgets() { _tabbedPanel->raise(); } _raiseEmojiSuggestions(); - if (_tabbedSelectorToggleTooltip) { - _tabbedSelectorToggleTooltip->raise(); - } _attachDragDocument->raise(); _attachDragPhoto->raise(); } @@ -1297,10 +1311,6 @@ void HistoryWidget::updateSendAction( } } -void HistoryWidget::updateRecentStickers() { - _tabbedSelector->refreshStickers(); -} - void HistoryWidget::sendActionDone(const MTPBool &result, mtpRequestId req) { for (auto i = _sendActionRequests.begin(), e = _sendActionRequests.end(); i != e; ++i) { if (i.value() == req) { @@ -1729,7 +1739,6 @@ void HistoryWidget::showHistory( _peer = session().data().peer(peerId); _channel = peerToChannel(_peer->id); _canSendMessages = _peer->canWrite(); - _tabbedSelector->setCurrentPeer(_peer); _contactStatus = std::make_unique( &controller()->window()->controller(), this, @@ -1741,6 +1750,8 @@ void HistoryWidget::showHistory( } else { _contactStatus = nullptr; } + refreshTabbedPanel(); + controller()->tabbedSelector()->setCurrentPeer(_peer); if (_peer) { _unblock->setText(((_peer->isUser() @@ -1818,8 +1829,6 @@ void HistoryWidget::showHistory( applyDraft(); _send->finishAnimating(); - _tabbedSelector->showMegagroupSet(_peer->asMegagroup()); - updateControlsGeometry(); connect(_scroll, SIGNAL(geometryChanged()), _list, SLOT(onParentGeometryChanged())); @@ -1854,7 +1863,6 @@ void HistoryWidget::showHistory( updateTopBarSelection(); clearFieldText(); - _tabbedSelector->showMegagroupSet(nullptr); doneShow(); } updateForwarding(); @@ -3860,20 +3868,36 @@ void HistoryWidget::pushTabbedSelectorToThirdSection( return; } session().settings().setTabbedReplacedWithInfo(false); - _tabbedSelectorToggle->setColorOverrides( - &st::historyAttachEmojiActive, - &st::historyRecordVoiceFgActive, - &st::historyRecordVoiceRippleBgActive); - auto destroyingPanel = std::move(_tabbedPanel); - auto memento = ChatHelpers::TabbedMemento( - destroyingPanel->takeSelector(), - crl::guard(this, [this]( - object_ptr selector) { - returnTabbedSelector(std::move(selector)); - })); controller()->resizeForThirdSection(); - controller()->showSection(std::move(memento), params.withThirdColumn()); - destroyingPanel.destroy(); + controller()->showSection( + ChatHelpers::TabbedMemento(), + params.withThirdColumn()); +} + +bool HistoryWidget::returnTabbedSelector() { + createTabbedPanel(); + moveFieldControls(); + return true; +} + +void HistoryWidget::createTabbedPanel() { + setTabbedPanel(std::make_unique( + this, + controller(), + controller()->tabbedSelector())); +} + +void HistoryWidget::setTabbedPanel(std::unique_ptr panel) { + _tabbedPanel = std::move(panel); + if (const auto raw = _tabbedPanel.get()) { + _tabbedSelectorToggle->installEventFilter(raw); + _tabbedSelectorToggle->setColorOverrides(nullptr, nullptr, nullptr); + } else { + _tabbedSelectorToggle->setColorOverrides( + &st::historyAttachEmojiActive, + &st::historyRecordVoiceFgActive, + &st::historyRecordVoiceRippleBgActive); + } } void HistoryWidget::toggleTabbedSelectorMode() { @@ -3891,18 +3915,6 @@ void HistoryWidget::toggleTabbedSelectorMode() { } } -void HistoryWidget::returnTabbedSelector( - object_ptr selector) { - _tabbedPanel.create( - this, - controller(), - std::move(selector)); - _tabbedSelectorToggle->installEventFilter(_tabbedPanel); - _tabbedSelectorToggle->setColorOverrides(nullptr, nullptr, nullptr); - _tabbedSelectorToggleTooltipShown = false; - moveFieldControls(); -} - void HistoryWidget::recountChatWidth() { auto layout = (width() < st::adaptiveChatWideWidth) ? Adaptive::ChatLayout::Normal @@ -3935,7 +3947,6 @@ void HistoryWidget::moveFieldControls() { auto right = st::historySendRight; _send->moveToRight(right, buttonsBottom); right += _send->width(); _tabbedSelectorToggle->moveToRight(right, buttonsBottom); - updateTabbedSelectorToggleTooltipGeometry(); _botKeyboardHide->moveToRight(right, buttonsBottom); right += _botKeyboardHide->width(); _botKeyboardShow->moveToRight(right, buttonsBottom); _botCommandStart->moveToRight(right, buttonsBottom); @@ -3989,15 +4000,6 @@ void HistoryWidget::moveFieldControls() { } } -void HistoryWidget::updateTabbedSelectorToggleTooltipGeometry() { - if (_tabbedSelectorToggleTooltip) { - auto toggle = _tabbedSelectorToggle->geometry(); - auto margin = st::historyAttachEmojiTooltipDelta; - auto margins = QMargins(margin, margin, margin, margin); - _tabbedSelectorToggleTooltip->pointAt(toggle.marginsRemoved(margins)); - } -} - void HistoryWidget::updateFieldSize() { auto kbShowShown = _history && !_kbShown && _keyboard->hasMarkup(); auto fieldWidth = width() - _attachToggle->width() - st::historySendRight; @@ -6861,4 +6863,6 @@ void HistoryWidget::synteticScrollToY(int y) { _synteticScrollEvent = false; } -HistoryWidget::~HistoryWidget() = default; +HistoryWidget::~HistoryWidget() { + setTabbedPanel(nullptr); +} diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index 4b023a287a..6d6f0f824f 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -91,7 +91,9 @@ class MessageField; class HistoryInner; struct HistoryMessageMarkupButton; -class HistoryWidget final : public Window::AbstractSectionWidget, public RPCSender { +class HistoryWidget final + : public Window::AbstractSectionWidget + , public RPCSender { Q_OBJECT public: @@ -128,10 +130,6 @@ public: void historyToDown(History *history); QRect historyRect() const; - void pushTabbedSelectorToThirdSection( - const Window::SectionShow ¶ms); - - void updateRecentStickers(); void updateFieldPlaceholder(); void updateStickersByEmoji(); @@ -244,6 +242,11 @@ public: bool sendExistingDocument(not_null document); bool sendExistingPhoto(not_null photo); + // Tabbed selector management. + void pushTabbedSelectorToThirdSection( + const Window::SectionShow ¶ms) override; + bool returnTabbedSelector() override; + // Float player interface. bool wheelEventFromFloatPlayer(QEvent *e) override; QRect rectForFloatPlayer() const override; @@ -357,6 +360,9 @@ private: friend inline constexpr bool is_flag_type(TextUpdateEvent) { return true; }; void initTabbedSelector(); + void refreshTabbedPanel(); + void createTabbedPanel(); + void setTabbedPanel(std::unique_ptr panel); void updateField(); void send(Api::SendOptions options); @@ -366,7 +372,6 @@ private: void handlePendingHistoryUpdate(); void fullPeerUpdated(PeerData *peer); void toggleTabbedSelectorMode(); - void returnTabbedSelector(object_ptr selector); void recountChatWidth(); void historyDownClicked(); void showNextUnreadMention(); @@ -486,8 +491,6 @@ private: // like send button, emoji button and others. void moveFieldControls(); void updateFieldSize(); - void updateTabbedSelectorToggleTooltipGeometry(); - void checkTabbedSelectorToggleTooltip(); bool canWriteMessage() const; std::optional writeRestriction() const; @@ -728,8 +731,6 @@ private: object_ptr _aboutProxyPromotion = { nullptr }; object_ptr _attachToggle; object_ptr _tabbedSelectorToggle; - object_ptr _tabbedSelectorToggleTooltip = { nullptr }; - bool _tabbedSelectorToggleTooltipShown = false; object_ptr _botKeyboardShow; object_ptr _botKeyboardHide; object_ptr _botCommandStart; @@ -763,8 +764,7 @@ private: QTimer _membersDropdownShowTimer; object_ptr _inlineResults = { nullptr }; - object_ptr _tabbedPanel; - QPointer _tabbedSelector; + std::unique_ptr _tabbedPanel; DragState _attachDragState; object_ptr _attachDragDocument, _attachDragPhoto; diff --git a/Telegram/SourceFiles/history/view/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/history_view_compose_controls.cpp index f57ac36b48..90b2fcab02 100644 --- a/Telegram/SourceFiles/history/view/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/history_view_compose_controls.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/input_fields.h" #include "ui/special_buttons.h" #include "lang/lang_keys.h" +#include "core/event_filter.h" #include "chat_helpers/tabbed_panel.h" #include "chat_helpers/tabbed_section.h" #include "chat_helpers/tabbed_selector.h" @@ -36,17 +37,18 @@ ComposeControls::ComposeControls( , _tabbedSelectorToggle(Ui::CreateChild( _wrap.get(), st::historyAttachEmoji)) -, _field(Ui::CreateChild( - _wrap.get(), - st::historyComposeField, - Ui::InputField::Mode::MultiLine, - tr::lng_message_ph())) -, _tabbedPanel(std::make_unique(parent, window)) -, _tabbedSelector(_tabbedPanel->getSelector()) { +, _field( + Ui::CreateChild( + _wrap.get(), + st::historyComposeField, + Ui::InputField::Mode::MultiLine, + tr::lng_message_ph())) { init(); } -ComposeControls::~ComposeControls() = default; +ComposeControls::~ComposeControls() { + setTabbedPanel(nullptr); +} Main::Session &ComposeControls::session() const { return _window->session(); @@ -138,10 +140,46 @@ void ComposeControls::initField() { } void ComposeControls::initTabbedSelector() { - _tabbedSelectorToggle->installEventFilter(_tabbedPanel.get()); + if (_window->hasTabbedSelectorOwnership()) { + createTabbedPanel(); + } else { + setTabbedPanel(nullptr); + } + _tabbedSelectorToggle->addClickHandler([=] { toggleTabbedSelectorMode(); }); + + const auto selector = _window->tabbedSelector(); + const auto wrap = _wrap.get(); + + Core::InstallEventFilter(wrap, selector, [=](not_null e) { + if (_tabbedPanel && e->type() == QEvent::ParentChange) { + setTabbedPanel(nullptr); + } + return false; + }); + + selector->emojiChosen( + ) | rpl::start_with_next([=](EmojiPtr emoji) { + Ui::InsertEmojiAtCursor(_field->textCursor(), emoji); + }, wrap->lifetime()); + + selector->fileChosen( + ) | rpl::start_with_next([=](not_null document) { + //sendExistingDocument(document); + }, wrap->lifetime()); + + selector->photoChosen( + ) | rpl::start_with_next([=](not_null photo) { + //sendExistingPhoto(photo); + }, wrap->lifetime()); + + selector->inlineResultChosen( + ) | rpl::start_with_next([=]( + ChatHelpers::TabbedSelector::InlineChosen data) { + //sendInlineResult(data.result, data.bot); + }, wrap->lifetime()); } void ComposeControls::updateControlsGeometry(QSize size) { @@ -205,15 +243,37 @@ void ComposeControls::pushTabbedSelectorToThirdSection( &st::historyAttachEmojiActive, &st::historyRecordVoiceFgActive, &st::historyRecordVoiceRippleBgActive); - auto destroyingPanel = std::move(_tabbedPanel); - auto memento = ChatHelpers::TabbedMemento( - destroyingPanel->takeSelector(), - crl::guard(_wrap.get(), [=]( - object_ptr selector) { - returnTabbedSelector(std::move(selector)); - })); _window->resizeForThirdSection(); - _window->showSection(std::move(memento), params.withThirdColumn()); + _window->showSection( + ChatHelpers::TabbedMemento(), + params.withThirdColumn()); +} + +bool ComposeControls::returnTabbedSelector() { + createTabbedPanel(); + updateOuterGeometry(_wrap->geometry()); + return true; +} + +void ComposeControls::createTabbedPanel() { + setTabbedPanel(std::make_unique( + _parent, + _window, + _window->tabbedSelector())); +} + +void ComposeControls::setTabbedPanel( + std::unique_ptr panel) { + _tabbedPanel = std::move(panel); + if (const auto raw = _tabbedPanel.get()) { + _tabbedSelectorToggle->installEventFilter(raw); + _tabbedSelectorToggle->setColorOverrides(nullptr, nullptr, nullptr); + } else { + _tabbedSelectorToggle->setColorOverrides( + &st::historyAttachEmojiActive, + &st::historyRecordVoiceFgActive, + &st::historyRecordVoiceRippleBgActive); + } } void ComposeControls::toggleTabbedSelectorMode() { @@ -231,18 +291,6 @@ void ComposeControls::toggleTabbedSelectorMode() { } } -void ComposeControls::returnTabbedSelector( - object_ptr selector) { - _tabbedPanel = std::make_unique( - _parent, - _window, - std::move(selector)); - _tabbedPanel->hide(); - _tabbedSelectorToggle->installEventFilter(_tabbedPanel.get()); - _tabbedSelectorToggle->setColorOverrides(nullptr, nullptr, nullptr); - updateOuterGeometry(_wrap->geometry()); -} - void ComposeControls::updateHeight() { const auto height = _field->height() + 2 * st::historySendPadding; _wrap->resize(_wrap->width(), height); diff --git a/Telegram/SourceFiles/history/view/history_view_compose_controls.h b/Telegram/SourceFiles/history/view/history_view_compose_controls.h index e417df1b17..d251d8c1d1 100644 --- a/Telegram/SourceFiles/history/view/history_view_compose_controls.h +++ b/Telegram/SourceFiles/history/view/history_view_compose_controls.h @@ -65,6 +65,9 @@ public: void focus(); [[nodiscard]] rpl::producer<> cancelRequests() const; + void pushTabbedSelectorToThirdSection(const Window::SectionShow ¶ms); + bool returnTabbedSelector(); + void showForGrab(); void showStarted(); void showFinished(); @@ -80,9 +83,8 @@ private: void escape(); void toggleTabbedSelectorMode(); - void pushTabbedSelectorToThirdSection(const Window::SectionShow ¶ms); - void returnTabbedSelector( - object_ptr selector); + void createTabbedPanel(); + void setTabbedPanel(std::unique_ptr panel); const not_null _parent; const not_null _window; @@ -96,7 +98,6 @@ private: const not_null _field; std::unique_ptr _inlineResults; std::unique_ptr _tabbedPanel; - const not_null _tabbedSelector; rpl::event_stream<> _cancelRequests; diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp index 1e87e97c2f..7c12f6910c 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp @@ -257,6 +257,15 @@ void ScheduledWidget::setInternalState( restoreState(memento); } +void ScheduledWidget::pushTabbedSelectorToThirdSection( + const Window::SectionShow ¶ms) { + _composeControls->pushTabbedSelectorToThirdSection(params); +} + +bool ScheduledWidget::returnTabbedSelector() { + return _composeControls->returnTabbedSelector(); +} + std::unique_ptr ScheduledWidget::createMemento() { auto result = std::make_unique(history()); saveState(result.get()); diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.h b/Telegram/SourceFiles/history/view/history_view_scheduled_section.h index a64b2b8349..38b6c98e57 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.h +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.h @@ -64,6 +64,11 @@ public: const QRect &geometry, not_null memento); + // Tabbed selector management. + void pushTabbedSelectorToThirdSection( + const Window::SectionShow ¶ms) override; + bool returnTabbedSelector() override; + // Float player interface. bool wheelEventFromFloatPlayer(QEvent *e) override; QRect rectForFloatPlayer() const override; diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp index 1a22689cca..4b2693be04 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp @@ -24,7 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "lang/lang_keys.h" #include "main/main_session.h" #include "mainwidget.h" -#include "window/main_window.h" +#include "mainwindow.h" #include "styles/style_overview.h" #include "styles/style_info.h" #include "platform/platform_info.h" diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index b8b2290e15..62fb273dbe 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -37,6 +37,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/section_memento.h" #include "window/section_widget.h" #include "window/window_connecting_widget.h" +#include "chat_helpers/tabbed_selector.h" // TabbedSelector::refreshStickers #include "chat_helpers/message_field.h" #include "chat_helpers/stickers.h" #include "info/info_memento.h" @@ -1667,11 +1668,7 @@ void MainWidget::ui_showPeerHistory( auto noPeer = !_history->peer(); auto onlyDialogs = noPeer && Adaptive::OneColumn(); - if (_mainSection) { - _mainSection->hide(); - _mainSection->deleteLater(); - _mainSection = nullptr; - } + _mainSection.destroy(); updateControlsGeometry(); @@ -1969,11 +1966,6 @@ void MainWidget::showNewSection( } updateControlsGeometry(); } else { - if (_mainSection) { - _mainSection->hide(); - _mainSection->deleteLater(); - _mainSection = nullptr; - } _mainSection = std::move(newMainSection); updateControlsGeometry(); _history->finishAnimating(); @@ -2688,6 +2680,12 @@ int MainWidget::contentScrollAddToY() const { return _contentScrollAddToY; } +void MainWidget::returnTabbedSelector() { + if (!_mainSection || !_mainSection->returnTabbedSelector()) { + _history->returnTabbedSelector(); + } +} + void MainWidget::keyPressEvent(QKeyEvent *e) { } @@ -3471,7 +3469,7 @@ void MainWidget::incrementSticker(DocumentData *sticker) { if (writeRecentStickers) { Local::writeRecentStickers(); } - _history->updateRecentStickers(); + _controller->tabbedSelector()->refreshStickers(); } void MainWidget::activate() { diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 1280276d3a..7f4aee12da 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -106,12 +106,14 @@ public: MainWidget(QWidget *parent, not_null controller); - Main::Session &session() const; + [[nodiscard]] Main::Session &session() const; - bool isMainSectionShown() const; - bool isThirdSectionShown() const; + [[nodiscard]] bool isMainSectionShown() const; + [[nodiscard]] bool isThirdSectionShown() const; - int contentScrollAddToY() const; + [[nodiscard]] int contentScrollAddToY() const; + + void returnTabbedSelector(); void showAnimated(const QPixmap &bgAnimCache, bool back = false); diff --git a/Telegram/SourceFiles/window/main_window.cpp b/Telegram/SourceFiles/window/main_window.cpp index c773580785..4644d3b8e5 100644 --- a/Telegram/SourceFiles/window/main_window.cpp +++ b/Telegram/SourceFiles/window/main_window.cpp @@ -656,9 +656,6 @@ void MainWindow::setInactivePress(bool inactive) { } } -MainWindow::~MainWindow() { - // We want to delete all widgets before the _controller. - _body.destroy(); -} +MainWindow::~MainWindow() = default; } // namespace Window diff --git a/Telegram/SourceFiles/window/main_window.h b/Telegram/SourceFiles/window/main_window.h index ccf06d31e4..2eacf8a8a5 100644 --- a/Telegram/SourceFiles/window/main_window.h +++ b/Telegram/SourceFiles/window/main_window.h @@ -92,6 +92,8 @@ public: virtual void updateWindowIcon(); + void clearWidgets(); + public slots: bool minimizeToTray(); void updateGlobalMenu() { @@ -115,7 +117,6 @@ protected: virtual void handleActiveChangedHook() { } - void clearWidgets(); virtual void clearWidgetsHook() { } diff --git a/Telegram/SourceFiles/window/section_widget.h b/Telegram/SourceFiles/window/section_widget.h index 96cb896d97..ecb747f354 100644 --- a/Telegram/SourceFiles/window/section_widget.h +++ b/Telegram/SourceFiles/window/section_widget.h @@ -39,23 +39,31 @@ public: , _controller(controller) { } - Main::Session &session() const; + [[nodiscard]] Main::Session &session() const; + + // Tabbed selector management. + virtual void pushTabbedSelectorToThirdSection( + const Window::SectionShow ¶ms) { + } + virtual bool returnTabbedSelector() { + return false; + } // Float player interface. virtual bool wheelEventFromFloatPlayer(QEvent *e) { return false; } - virtual QRect rectForFloatPlayer() const { + [[nodiscard]] virtual QRect rectForFloatPlayer() const { return mapToGlobal(rect()); } protected: - not_null controller() const { + [[nodiscard]] not_null controller() const { return _controller; } private: - not_null _controller; + const not_null _controller; }; diff --git a/Telegram/SourceFiles/window/window_controller.cpp b/Telegram/SourceFiles/window/window_controller.cpp index 5b1cc7a320..020d45cc97 100644 --- a/Telegram/SourceFiles/window/window_controller.cpp +++ b/Telegram/SourceFiles/window/window_controller.cpp @@ -28,7 +28,10 @@ Controller::Controller(not_null account) _widget.init(); } -Controller::~Controller() = default; +Controller::~Controller() { + // We want to delete all widgets before the _sessionController. + _widget.clearWidgets(); +} void Controller::firstShow() { _widget.firstShow(); diff --git a/Telegram/SourceFiles/window/window_controller.h b/Telegram/SourceFiles/window/window_controller.h index e4c48b76d6..99b6888c0b 100644 --- a/Telegram/SourceFiles/window/window_controller.h +++ b/Telegram/SourceFiles/window/window_controller.h @@ -69,8 +69,8 @@ private: anim::type animated); not_null _account; - std::unique_ptr _sessionController; ::MainWindow _widget; + std::unique_ptr _sessionController; rpl::lifetime _lifetime; diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index 58100acdc1..31033cc431 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_channel.h" #include "data/data_chat.h" #include "passport/passport_form_controller.h" +#include "chat_helpers/tabbed_selector.h" #include "core/shortcuts.h" #include "base/unixtime.h" #include "boxes/calendar_box.h" @@ -99,9 +100,11 @@ void SessionNavigation::showSettings(const SectionShow ¶ms) { SessionController::SessionController( not_null session, - not_null window) + not_null<::MainWindow*> window) : SessionNavigation(session) -, _window(window) { +, _window(window) +, _tabbedSelector( + std::make_unique(window, this)) { init(); subscribe(session->api().fullPeerUpdated(), [=](PeerData *peer) { @@ -122,6 +125,28 @@ SessionController::SessionController( }, lifetime()); } +auto SessionController::tabbedSelector() const +-> not_null { + return _tabbedSelector.get(); +} + +void SessionController::takeTabbedSelectorOwnershipFrom( + not_null parent) { + if (_tabbedSelector->parent() == parent) { + if (const auto chats = _window->chatsWidget()) { + chats->returnTabbedSelector(); + } + if (_tabbedSelector->parent() == parent) { + _tabbedSelector->hide(); + _tabbedSelector->setParent(window()); + } + } +} + +bool SessionController::hasTabbedSelectorOwnership() const { + return (_tabbedSelector->parent() == window()); +} + void SessionController::showEditPeerBox(PeerData *peer) { _showEditPeer = peer; session().api().requestFullPeer(peer); diff --git a/Telegram/SourceFiles/window/window_session_controller.h b/Telegram/SourceFiles/window/window_session_controller.h index 6dd3f18056..d27f854ddc 100644 --- a/Telegram/SourceFiles/window/window_session_controller.h +++ b/Telegram/SourceFiles/window/window_session_controller.h @@ -13,9 +13,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "dialogs/dialogs_key.h" class MainWidget; +class MainWindow; class HistoryMessage; class HistoryService; +namespace ChatHelpers { +class TabbedSelector; +} // namespace ChatHelpers + namespace Main { class Session; } // namespace Main @@ -146,12 +151,17 @@ class SessionController public: SessionController( not_null session, - not_null window); + not_null<::MainWindow*> window); - not_null window() const { + [[nodiscard]] not_null<::MainWindow*> window() const { return _window; } + [[nodiscard]] auto tabbedSelector() const + -> not_null; + void takeTabbedSelectorOwnershipFrom(not_null parent); + [[nodiscard]] bool hasTabbedSelectorOwnership() const; + // This is needed for History TopBar updating when searchInChat // is changed in the Dialogs::Widget of the current window. rpl::variable searchInChat; @@ -292,7 +302,7 @@ private: void pushToChatEntryHistory(Dialogs::RowDescriptor row); bool chatEntryHistoryMove(int steps); - const not_null _window; + const not_null<::MainWindow*> _window; std::unique_ptr _passportForm; @@ -300,6 +310,9 @@ private: base::Observable _gifPauseLevelChanged; base::Observable _floatPlayerAreaUpdated; + // Depends on _gifPause*. + const std::unique_ptr _tabbedSelector; + rpl::variable _activeChatEntry; base::Variable _dialogsListFocused = { false }; base::Variable _dialogsListDisplayForced = { false };