From 7d22c631ca7308008b84ed625eaf65bf15639bd6 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 24 Dec 2020 13:30:05 +0400 Subject: [PATCH] Fix voice chat members context menu. --- Telegram/SourceFiles/boxes/peer_list_box.cpp | 63 ++++++++++++------- Telegram/SourceFiles/boxes/peer_list_box.h | 17 +++++ .../SourceFiles/calls/calls_group_members.cpp | 62 ++++++++++-------- Telegram/SourceFiles/calls/calls_top_bar.cpp | 3 +- 4 files changed, 96 insertions(+), 49 deletions(-) diff --git a/Telegram/SourceFiles/boxes/peer_list_box.cpp b/Telegram/SourceFiles/boxes/peer_list_box.cpp index acfb131f4..56e0f1568 100644 --- a/Telegram/SourceFiles/boxes/peer_list_box.cpp +++ b/Telegram/SourceFiles/boxes/peer_list_box.cpp @@ -1229,37 +1229,56 @@ void PeerListContent::mousePressReleased(Qt::MouseButton button) { } } -void PeerListContent::contextMenuEvent(QContextMenuEvent *e) { +void PeerListContent::showRowMenu( + not_null row, + Fn)> destroyed) { + showRowMenu(findRowIndex(row), QCursor::pos(), std::move(destroyed)); +} + +bool PeerListContent::showRowMenu( + RowIndex index, + QPoint globalPos, + Fn)> destroyed) { if (_contextMenu) { - _contextMenu->deleteLater(); + _contextMenu->setDestroyedCallback(nullptr); _contextMenu = nullptr; } setContexted(Selected()); - if (e->reason() == QContextMenuEvent::Mouse) { - handleMouseMove(e->globalPos()); - } - - setContexted(_selected); if (_pressButton != Qt::LeftButton) { mousePressReleased(_pressButton); } - if (const auto row = getRow(_contexted.index)) { - _contextMenu = _controller->rowContextMenu(this, row); - if (_contextMenu) { - _contextMenu->setDestroyedCallback(crl::guard( - this, - [this] { - setContexted(Selected()); - handleMouseMove(QCursor::pos()); - })); - _contextMenu->popup(e->globalPos()); - e->accept(); - } else { + const auto row = getRow(index); + if (!row) { + return false; + } + + _contextMenu = _controller->rowContextMenu(this, row); + const auto raw = _contextMenu.get(); + if (!raw) { + return false; + } + + setContexted({ index, false }); + raw->setDestroyedCallback(crl::guard( + this, + [=] { setContexted(Selected()); - } - } else { - setContexted(Selected()); + handleMouseMove(QCursor::pos()); + if (destroyed) { + destroyed(raw); + } + })); + raw->popup(globalPos); + return true; +} + +void PeerListContent::contextMenuEvent(QContextMenuEvent *e) { + if (e->reason() == QContextMenuEvent::Mouse) { + handleMouseMove(e->globalPos()); + } + if (showRowMenu(_selected.index, e->globalPos())) { + e->accept(); } } diff --git a/Telegram/SourceFiles/boxes/peer_list_box.h b/Telegram/SourceFiles/boxes/peer_list_box.h index 0a8332c4e..eed2af665 100644 --- a/Telegram/SourceFiles/boxes/peer_list_box.h +++ b/Telegram/SourceFiles/boxes/peer_list_box.h @@ -300,6 +300,9 @@ public: peerListFinishSelectedRowsBunch(); } + virtual void peerListShowRowMenu( + not_null row, + Fn)> destroyed) = 0; virtual int peerListSelectedRowsCount() = 0; virtual std::unique_ptr peerListSaveState() const = 0; virtual void peerListRestoreState( @@ -557,6 +560,10 @@ public: std::unique_ptr saveState() const; void restoreState(std::unique_ptr state); + void showRowMenu( + not_null row, + Fn)> destroyed); + auto scrollToRequests() const { return _scrollToRequests.events(); } @@ -640,6 +647,11 @@ private: RowIndex findRowIndex(not_null row, RowIndex hint = RowIndex()); QRect getActiveActionRect(not_null row, RowIndex index) const; + bool showRowMenu( + RowIndex index, + QPoint globalPos, + Fn)> destroyed = nullptr); + crl::time paintRow(Painter &p, crl::time ms, RowIndex index); void addRowEntry(not_null row); @@ -823,6 +835,11 @@ public: std::unique_ptr state) override { _content->restoreState(std::move(state)); } + void peerListShowRowMenu( + not_null row, + Fn)> destroyed) override { + _content->showRowMenu(row, std::move(destroyed)); + } protected: not_null content() const { diff --git a/Telegram/SourceFiles/calls/calls_group_members.cpp b/Telegram/SourceFiles/calls/calls_group_members.cpp index 089bb5c50..a68dcd754 100644 --- a/Telegram/SourceFiles/calls/calls_group_members.cpp +++ b/Telegram/SourceFiles/calls/calls_group_members.cpp @@ -243,6 +243,9 @@ private: void prepareRows(not_null real); //void repaintByTimer(); + [[nodiscard]] base::unique_qptr createRowContextMenu( + QWidget *parent, + not_null row); void setupListChangeViewers(not_null call); void subscribeToChanges(not_null real); void updateRow( @@ -638,10 +641,7 @@ MembersController::MembersController( } MembersController::~MembersController() { - if (_menu) { - _menu->setDestroyedCallback(nullptr); - _menu = nullptr; - } + base::take(_menu); } void MembersController::setupListChangeViewers(not_null call) { @@ -1002,29 +1002,20 @@ auto MembersController::kickMemberRequests() const } void MembersController::rowClicked(not_null row) { - if (_menu) { - _menu->setDestroyedCallback(nullptr); - _menu->deleteLater(); - _menu = nullptr; - } - _menu = rowContextMenu(_menuParent, row); - if (const auto raw = _menu.get()) { - raw->setDestroyedCallback([=] { - if (_menu && _menu.get() != raw) { - return; - } - auto saved = base::take(_menu); - for (const auto peer : base::take(_menuCheckRowsAfterHidden)) { - if (const auto row = findRow(peer->asUser())) { - if (row->speaking()) { - checkSpeakingRowPosition(row); - } + delegate()->peerListShowRowMenu(row, [=](not_null menu) { + if (!_menu || _menu.get() != menu) { + return; + } + auto saved = base::take(_menu); + for (const auto peer : base::take(_menuCheckRowsAfterHidden)) { + if (const auto row = findRow(peer->asUser())) { + if (row->speaking()) { + checkSpeakingRowPosition(row); } } - _menu = std::move(saved); - }); - raw->popup(QCursor::pos()); - } + } + _menu = std::move(saved); + }); } void MembersController::rowActionClicked( @@ -1035,6 +1026,23 @@ void MembersController::rowActionClicked( base::unique_qptr MembersController::rowContextMenu( QWidget *parent, not_null row) { + auto result = createRowContextMenu(parent, row); + + if (result) { + // First clear _menu value, so that we don't check row positions yet. + base::take(_menu); + + // Here unique_qptr is used like a shared pointer, where + // not the last destroyed pointer destroys the object, but the first. + _menu = base::unique_qptr(result.get()); + } + + return result; +} + +base::unique_qptr MembersController::createRowContextMenu( + QWidget *parent, + not_null row) { Expects(row->peer()->isUser()); if (row->peer()->isSelf()) { @@ -1125,7 +1133,9 @@ base::unique_qptr MembersController::rowContextMenu( _kickMemberRequests.fire_copy(user); }); - if (_peer->canManageGroupCall() && (!admin || mute)) { + if ((muteState != Row::State::Invited) + && _peer->canManageGroupCall() + && (!admin || mute)) { result->addAction( (mute ? tr::lng_group_call_context_mute(tr::now) diff --git a/Telegram/SourceFiles/calls/calls_top_bar.cpp b/Telegram/SourceFiles/calls/calls_top_bar.cpp index e5ab99765..ae8cf508f 100644 --- a/Telegram/SourceFiles/calls/calls_top_bar.cpp +++ b/Telegram/SourceFiles/calls/calls_top_bar.cpp @@ -689,7 +689,8 @@ void TopBar::updateControlsGeometry() { left += _durationLabel->width() + st::callBarSkip; } if (!_userpics.isNull()) { - left += _userpics.width() / _userpics.devicePixelRatio(); + left += (_userpics.width() / _userpics.devicePixelRatio()) + + st::callBarSkip; } if (_signalBars) { _signalBars->moveToLeft(left, (height() - _signalBars->height()) / 2);