mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-01-11 17:29:46 +00:00
Add context menu to info shared media.
This commit is contained in:
parent
9a988d89e3
commit
f5c5c32d1d
@ -956,9 +956,9 @@ void PeerListContent::mousePressReleased(Qt::MouseButton button) {
|
||||
}
|
||||
|
||||
void PeerListContent::contextMenuEvent(QContextMenuEvent *e) {
|
||||
if (_menu) {
|
||||
_menu->deleteLater();
|
||||
_menu = nullptr;
|
||||
if (_contextMenu) {
|
||||
_contextMenu->deleteLater();
|
||||
_contextMenu = nullptr;
|
||||
}
|
||||
setContexted(Selected());
|
||||
if (e->reason() == QContextMenuEvent::Mouse) {
|
||||
@ -971,15 +971,15 @@ void PeerListContent::contextMenuEvent(QContextMenuEvent *e) {
|
||||
}
|
||||
|
||||
if (auto row = getRow(_contexted.index)) {
|
||||
_menu = _controller->rowContextMenu(row);
|
||||
if (_menu) {
|
||||
_menu->setDestroyedCallback(base::lambda_guarded(
|
||||
_contextMenu = _controller->rowContextMenu(row);
|
||||
if (_contextMenu) {
|
||||
_contextMenu->setDestroyedCallback(base::lambda_guarded(
|
||||
this,
|
||||
[this] {
|
||||
setContexted(Selected());
|
||||
handleMouseMove(QCursor::pos());
|
||||
}));
|
||||
_menu->popup(e->globalPos());
|
||||
_contextMenu->popup(e->globalPos());
|
||||
e->accept();
|
||||
}
|
||||
}
|
||||
|
@ -604,7 +604,7 @@ private:
|
||||
|
||||
std::vector<std::unique_ptr<PeerListRow>> _searchRows;
|
||||
base::Timer _repaintByStatus;
|
||||
QPointer<Ui::PopupMenu> _menu;
|
||||
QPointer<Ui::PopupMenu> _contextMenu;
|
||||
|
||||
};
|
||||
|
||||
|
@ -26,11 +26,17 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "storage/file_download.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "auth_session.h"
|
||||
#include "mainwidget.h"
|
||||
#include "window/main_window.h"
|
||||
#include "styles/style_overview.h"
|
||||
#include "styles/style_info.h"
|
||||
#include "boxes/peer_list_box.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "info/info_top_bar_override.h"
|
||||
#include "core/file_utilities.h"
|
||||
|
||||
namespace Layout = Overview::Layout;
|
||||
|
||||
@ -634,6 +640,19 @@ auto ListWidget::collectSelectedItems() const -> SelectedItems {
|
||||
return items;
|
||||
}
|
||||
|
||||
SelectedItemSet ListWidget::collectSelectedSet() const {
|
||||
auto items = SelectedItemSet();
|
||||
if (hasSelectedItems()) {
|
||||
for (auto &data : _selected) {
|
||||
auto fullId = computeFullId(data.first);
|
||||
if (auto item = App::histItemById(fullId)) {
|
||||
items.insert(items.size(), item);
|
||||
}
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
void ListWidget::pushSelectedItems() {
|
||||
_selectedListStream.fire(collectSelectedItems());
|
||||
}
|
||||
@ -1061,6 +1080,260 @@ void ListWidget::mouseDoubleClickEvent(QMouseEvent *e) {
|
||||
trySwitchToWordSelection();
|
||||
}
|
||||
|
||||
void ListWidget::showContextMenu(
|
||||
QContextMenuEvent *e,
|
||||
ContextMenuSource source) {
|
||||
if (_contextMenu) {
|
||||
_contextMenu->deleteLater();
|
||||
_contextMenu = nullptr;
|
||||
repaintItem(_contextUniversalId);
|
||||
}
|
||||
if (e->reason() == QContextMenuEvent::Mouse) {
|
||||
mouseActionUpdate(e->globalPos());
|
||||
}
|
||||
|
||||
auto item = App::histItemById(computeFullId(_overState.itemId));
|
||||
if (!item || !_overState.inside) {
|
||||
return;
|
||||
}
|
||||
auto universalId = _contextUniversalId = _overState.itemId;
|
||||
|
||||
enum class SelectionState {
|
||||
NoSelectedItems,
|
||||
NotOverSelectedItems,
|
||||
OverSelectedItems,
|
||||
NotOverSelectedText,
|
||||
OverSelectedText,
|
||||
};
|
||||
auto overSelected = SelectionState::NoSelectedItems;
|
||||
if (source == ContextMenuSource::Touch) {
|
||||
if (hasSelectedItems()) {
|
||||
overSelected = SelectionState::OverSelectedItems;
|
||||
} else if (hasSelectedText()) {
|
||||
overSelected = SelectionState::OverSelectedItems;
|
||||
}
|
||||
} else if (hasSelectedText()) {
|
||||
// #TODO text selection
|
||||
} else if (hasSelectedItems()) {
|
||||
auto it = _selected.find(_overState.itemId);
|
||||
if (isSelectedItem(it) && _overState.inside) {
|
||||
overSelected = SelectionState::OverSelectedItems;
|
||||
} else {
|
||||
overSelected = SelectionState::NotOverSelectedItems;
|
||||
}
|
||||
}
|
||||
|
||||
auto canDeleteAll = [&] {
|
||||
return base::find_if(_selected, [](auto &item) {
|
||||
return !item.second.canDelete;
|
||||
}) == _selected.end();
|
||||
};
|
||||
auto canForwardAll = [&] {
|
||||
return base::find_if(_selected, [](auto &item) {
|
||||
return !item.second.canForward;
|
||||
}) == _selected.end();
|
||||
};
|
||||
|
||||
auto link = ClickHandler::getActive();
|
||||
|
||||
_contextMenu = new Ui::PopupMenu(nullptr);
|
||||
_contextMenu->addAction(
|
||||
lang(lng_context_to_msg),
|
||||
[itemFullId = item->fullId()] {
|
||||
if (auto item = App::histItemById(itemFullId)) {
|
||||
Ui::showPeerHistoryAtItem(item);
|
||||
}
|
||||
});
|
||||
|
||||
auto photoLink = dynamic_cast<PhotoClickHandler*>(link.data());
|
||||
auto fileLink = dynamic_cast<DocumentClickHandler*>(link.data());
|
||||
if (photoLink || fileLink) {
|
||||
auto [isVideo, isVoice, isSong] = [&] {
|
||||
if (fileLink) {
|
||||
auto document = fileLink->document();
|
||||
return std::make_tuple(
|
||||
document->isVideo(),
|
||||
(document->voice() != nullptr),
|
||||
(document->song() != nullptr)
|
||||
);
|
||||
}
|
||||
return std::make_tuple(false, false, false);
|
||||
}();
|
||||
|
||||
if (photoLink) {
|
||||
} else {
|
||||
if (auto document = fileLink->document()) {
|
||||
if (document->loading()) {
|
||||
_contextMenu->addAction(
|
||||
lang(lng_context_cancel_download),
|
||||
[document] {
|
||||
document->cancel();
|
||||
});
|
||||
} else {
|
||||
auto filepath = document->filepath(DocumentData::FilePathResolveChecked);
|
||||
if (!filepath.isEmpty()) {
|
||||
auto handler = App::LambdaDelayed(
|
||||
st::defaultDropdownMenu.menu.ripple.hideDuration,
|
||||
this,
|
||||
[filepath] {
|
||||
File::ShowInFolder(filepath);
|
||||
});
|
||||
_contextMenu->addAction(
|
||||
lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld)
|
||||
? lng_context_show_in_finder
|
||||
: lng_context_show_in_folder),
|
||||
std::move(handler));
|
||||
}
|
||||
auto handler = App::LambdaDelayed(
|
||||
st::defaultDropdownMenu.menu.ripple.hideDuration,
|
||||
this,
|
||||
[document] {
|
||||
DocumentSaveClickHandler::doSave(document, true);
|
||||
});
|
||||
_contextMenu->addAction(
|
||||
lang(isVideo
|
||||
? lng_context_save_video
|
||||
: isVoice
|
||||
? lng_context_save_audio
|
||||
: isSong
|
||||
? lng_context_save_audio_file
|
||||
: lng_context_save_file),
|
||||
std::move(handler));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (link) {
|
||||
auto linkCopyToClipboardText
|
||||
= link->copyToClipboardContextItemText();
|
||||
if (!linkCopyToClipboardText.isEmpty()) {
|
||||
_contextMenu->addAction(
|
||||
linkCopyToClipboardText,
|
||||
[link] {
|
||||
link->copyToClipboard();
|
||||
});
|
||||
}
|
||||
}
|
||||
if (overSelected == SelectionState::OverSelectedItems) {
|
||||
if (canForwardAll()) {
|
||||
_contextMenu->addAction(
|
||||
lang(lng_context_forward_selected),
|
||||
base::lambda_guarded(this, [this] {
|
||||
forwardSelected();
|
||||
}));
|
||||
}
|
||||
if (canDeleteAll()) {
|
||||
_contextMenu->addAction(
|
||||
lang(lng_context_delete_selected),
|
||||
base::lambda_guarded(this, [this] {
|
||||
deleteSelected();
|
||||
}));
|
||||
}
|
||||
_contextMenu->addAction(
|
||||
lang(lng_context_clear_selection),
|
||||
base::lambda_guarded(this, [this] {
|
||||
clearSelected();
|
||||
}));
|
||||
} else {
|
||||
if (overSelected != SelectionState::NotOverSelectedItems) {
|
||||
if (item->canForward()) {
|
||||
_contextMenu->addAction(
|
||||
lang(lng_context_forward_msg),
|
||||
base::lambda_guarded(this, [this, universalId] {
|
||||
forwardItem(universalId);
|
||||
}));
|
||||
}
|
||||
if (item->canDelete()) {
|
||||
_contextMenu->addAction(
|
||||
lang(lng_context_delete_msg),
|
||||
base::lambda_guarded(this, [this, universalId] {
|
||||
deleteItem(universalId);
|
||||
}));
|
||||
}
|
||||
}
|
||||
_contextMenu->addAction(
|
||||
lang(lng_context_select_msg),
|
||||
base::lambda_guarded(this, [this, universalId] {
|
||||
if (hasSelectedText()) {
|
||||
clearSelected();
|
||||
} else if (_selected.size() == MaxSelectedItems) {
|
||||
return;
|
||||
} else if (_selected.empty()) {
|
||||
update();
|
||||
}
|
||||
applyItemSelection(universalId, FullSelection);
|
||||
}));
|
||||
}
|
||||
|
||||
_contextMenu->setDestroyedCallback(base::lambda_guarded(
|
||||
this,
|
||||
[this, universalId] {
|
||||
_contextMenu = nullptr;
|
||||
mouseActionUpdate(QCursor::pos());
|
||||
repaintItem(universalId);
|
||||
}));
|
||||
_contextMenu->popup(e->globalPos());
|
||||
e->accept();
|
||||
}
|
||||
|
||||
void ListWidget::contextMenuEvent(QContextMenuEvent *e) {
|
||||
showContextMenu(
|
||||
e,
|
||||
(e->reason() == QContextMenuEvent::Mouse)
|
||||
? ContextMenuSource::Mouse
|
||||
: ContextMenuSource::Other);
|
||||
}
|
||||
|
||||
void ListWidget::forwardSelected() {
|
||||
forwardItems(collectSelectedSet());
|
||||
}
|
||||
|
||||
void ListWidget::forwardItem(UniversalMsgId universalId) {
|
||||
if (auto item = App::histItemById(computeFullId(universalId))) {
|
||||
auto items = SelectedItemSet();
|
||||
items.insert(0, item);
|
||||
forwardItems(std::move(items));
|
||||
}
|
||||
}
|
||||
|
||||
void ListWidget::forwardItems(SelectedItemSet items) {
|
||||
if (items.empty()) {
|
||||
return;
|
||||
}
|
||||
auto that = weak(this);
|
||||
auto controller = std::make_unique<ChooseRecipientBoxController>(
|
||||
[that, items = std::move(items)](not_null<PeerData*> peer) {
|
||||
App::main()->setForwardDraft(peer->id, items);
|
||||
if (that) {
|
||||
that->clearSelected();
|
||||
}
|
||||
});
|
||||
Ui::show(Box<PeerListBox>(
|
||||
std::move(controller),
|
||||
[](not_null<PeerListBox*> box) {
|
||||
box->addButton(langFactory(lng_cancel), [box] {
|
||||
box->closeBox();
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
void ListWidget::deleteSelected() {
|
||||
deleteItems(collectSelectedSet());
|
||||
}
|
||||
|
||||
void ListWidget::deleteItem(UniversalMsgId universalId) {
|
||||
if (auto item = App::histItemById(computeFullId(universalId))) {
|
||||
auto items = SelectedItemSet();
|
||||
items.insert(0, item);
|
||||
deleteItems(std::move(items));
|
||||
}
|
||||
}
|
||||
|
||||
void ListWidget::deleteItems(SelectedItemSet items) {
|
||||
if (!items.empty()) {
|
||||
Ui::show(Box<DeleteMessagesBox>(items));
|
||||
}
|
||||
}
|
||||
|
||||
void ListWidget::trySwitchToWordSelection() {
|
||||
auto selectingSome = (_mouseAction == MouseAction::Selecting)
|
||||
&& hasSelectedText();
|
||||
|
@ -87,6 +87,7 @@ protected:
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
void mouseDoubleClickEvent(QMouseEvent *e) override;
|
||||
void contextMenuEvent(QContextMenuEvent *e) override;
|
||||
void enterEventHook(QEvent *e) override;
|
||||
void leaveEventHook(QEvent *e) override;
|
||||
|
||||
@ -144,6 +145,11 @@ private:
|
||||
}
|
||||
|
||||
};
|
||||
enum class ContextMenuSource {
|
||||
Mouse,
|
||||
Touch,
|
||||
Other,
|
||||
};
|
||||
|
||||
void start();
|
||||
int recountHeight();
|
||||
@ -173,6 +179,7 @@ private:
|
||||
Type type);
|
||||
|
||||
SelectedItems collectSelectedItems() const;
|
||||
SelectedItemSet collectSelectedSet() const;
|
||||
void pushSelectedItems();
|
||||
FullMsgId computeFullId(UniversalMsgId universalId) const;
|
||||
bool hasSelected() const;
|
||||
@ -183,6 +190,12 @@ private:
|
||||
bool hasSelectedText() const;
|
||||
bool hasSelectedItems() const;
|
||||
void clearSelected();
|
||||
void forwardSelected();
|
||||
void forwardItem(UniversalMsgId universalId);
|
||||
void forwardItems(SelectedItemSet items);
|
||||
void deleteSelected();
|
||||
void deleteItem(UniversalMsgId universalId);
|
||||
void deleteItems(SelectedItemSet items);
|
||||
void applyItemSelection(
|
||||
UniversalMsgId universalId,
|
||||
TextSelection selection);
|
||||
@ -238,6 +251,9 @@ private:
|
||||
void mouseActionCancel();
|
||||
void performDrag();
|
||||
style::cursor computeMouseCursor() const;
|
||||
void showContextMenu(
|
||||
QContextMenuEvent *e,
|
||||
ContextMenuSource source);
|
||||
|
||||
void updateDragSelection();
|
||||
void clearDragSelection();
|
||||
@ -271,6 +287,7 @@ private:
|
||||
CursorState _overState;
|
||||
CursorState _pressState;
|
||||
BaseLayout *_overLayout = nullptr;
|
||||
UniversalMsgId _contextUniversalId = 0;
|
||||
HistoryCursorState _mouseCursorState = HistoryDefaultCursorState;
|
||||
uint16 _mouseTextSymbol = 0;
|
||||
bool _pressWasInactive = false;
|
||||
@ -281,7 +298,6 @@ private:
|
||||
DragSelectAction _dragSelectAction = DragSelectAction::None;
|
||||
bool _wasSelectedText = false; // was some text selected in current drag action
|
||||
Ui::PopupMenu *_contextMenu = nullptr;
|
||||
ClickHandlerPtr _contextMenuLink;
|
||||
|
||||
QPoint _trippleClickPoint;
|
||||
TimeMs _trippleClickStartTime = 0;
|
||||
|
@ -334,6 +334,9 @@ void Cover::refreshStatusText() {
|
||||
refreshStatusGeometry(width());
|
||||
}
|
||||
|
||||
Cover::~Cover() {
|
||||
}
|
||||
|
||||
void Cover::refreshNameGeometry(int newWidth) {
|
||||
auto nameWidth = newWidth
|
||||
- st::infoProfileNameLeft
|
||||
|
@ -70,6 +70,8 @@ public:
|
||||
SectionWithToggle::setToggleShown(std::move(shown)));
|
||||
}
|
||||
|
||||
~Cover();
|
||||
|
||||
private:
|
||||
void setupChildGeometry();
|
||||
void initViewers();
|
||||
|
Loading…
Reference in New Issue
Block a user