added rightclicking selections to copy them

This commit is contained in:
fourtf 2018-06-04 14:39:26 +02:00
parent 2299030deb
commit 829809b0e1
5 changed files with 210 additions and 155 deletions

View file

@ -216,7 +216,7 @@ public:
if (this->data.caller != nullptr) { if (this->data.caller != nullptr) {
QObject::connect(worker, &NetworkWorker::doneUrl, this->data.caller, QObject::connect(worker, &NetworkWorker::doneUrl, this->data.caller,
[ onFinished, data = this->data ](auto reply) mutable { [onFinished, data = this->data](auto reply) mutable {
if (reply->error() != QNetworkReply::NetworkError::NoError) { if (reply->error() != QNetworkReply::NetworkError::NoError) {
// TODO: We might want to call an onError callback here // TODO: We might want to call an onError callback here
return; return;
@ -238,7 +238,7 @@ public:
QObject::connect( QObject::connect(
&requester, &NetworkRequester::requestUrl, worker, &requester, &NetworkRequester::requestUrl, worker,
[ timer, data = std::move(this->data), worker, onFinished{std::move(onFinished)} ]() { [timer, data = std::move(this->data), worker, onFinished{std::move(onFinished)}]() {
QNetworkReply *reply = NetworkManager::NaM.get(data.request); QNetworkReply *reply = NetworkManager::NaM.get(data.request);
if (timer != nullptr) { if (timer != nullptr) {
@ -253,21 +253,21 @@ public:
data.onReplyCreated(reply); data.onReplyCreated(reply);
} }
QObject::connect(reply, &QNetworkReply::finished, worker, [ QObject::connect(reply, &QNetworkReply::finished, worker,
data = std::move(data), worker, reply, onFinished = std::move(onFinished) [data = std::move(data), worker, reply,
]() mutable { onFinished = std::move(onFinished)]() mutable {
if (data.caller == nullptr) { if (data.caller == nullptr) {
QByteArray bytes = reply->readAll(); QByteArray bytes = reply->readAll();
data.writeToCache(bytes); data.writeToCache(bytes);
onFinished(bytes); onFinished(bytes);
reply->deleteLater(); reply->deleteLater();
} else { } else {
emit worker->doneUrl(reply); emit worker->doneUrl(reply);
} }
delete worker; delete worker;
}); });
}); });
emit requester.requestUrl(); emit requester.requestUrl();
@ -276,8 +276,7 @@ public:
template <typename FinishedCallback> template <typename FinishedCallback>
void getJSON(FinishedCallback onFinished) void getJSON(FinishedCallback onFinished)
{ {
this->get([onFinished{std::move(onFinished)}](const QByteArray &bytes)->bool { this->get([onFinished{std::move(onFinished)}](const QByteArray &bytes) -> bool {
auto object = parseJSONFromData(bytes); auto object = parseJSONFromData(bytes);
onFinished(object); onFinished(object);
@ -290,7 +289,7 @@ public:
template <typename FinishedCallback> template <typename FinishedCallback>
void getJSON2(FinishedCallback onFinished) void getJSON2(FinishedCallback onFinished)
{ {
this->get([onFinished{std::move(onFinished)}](const QByteArray &bytes)->bool { this->get([onFinished{std::move(onFinished)}](const QByteArray &bytes) -> bool {
auto object = parseJSONFromData2(bytes); auto object = parseJSONFromData2(bytes);
onFinished(object); onFinished(object);
@ -371,8 +370,8 @@ private:
worker->moveToThread(&NetworkManager::workerThread); worker->moveToThread(&NetworkManager::workerThread);
if (this->data.caller != nullptr) { if (this->data.caller != nullptr) {
QObject::connect(worker, &NetworkWorker::doneUrl, QObject::connect(worker, &NetworkWorker::doneUrl, this->data.caller,
this->data.caller, [data = this->data](auto reply) mutable { [data = this->data](auto reply) mutable {
if (reply->error() != QNetworkReply::NetworkError::NoError) { if (reply->error() != QNetworkReply::NetworkError::NoError) {
if (data.onError) { if (data.onError) {
data.onError(reply->error()); data.onError(reply->error());
@ -395,7 +394,7 @@ private:
} }
QObject::connect(&requester, &NetworkRequester::requestUrl, worker, QObject::connect(&requester, &NetworkRequester::requestUrl, worker,
[ timer, data = std::move(this->data), worker ]() { [timer, data = std::move(this->data), worker]() {
QNetworkReply *reply = nullptr; QNetworkReply *reply = nullptr;
switch (data.requestType) { switch (data.requestType) {
case GetRequest: { case GetRequest: {
@ -431,11 +430,16 @@ private:
} }
QObject::connect(reply, &QNetworkReply::finished, worker, QObject::connect(reply, &QNetworkReply::finished, worker,
[ data = std::move(data), worker, reply ]() mutable { [data = std::move(data), worker, reply]() mutable {
if (data.caller == nullptr) { if (data.caller == nullptr) {
QByteArray bytes = reply->readAll(); QByteArray bytes = reply->readAll();
data.writeToCache(bytes); data.writeToCache(bytes);
// data.onSuccess(parseJSONFromData2(bytes));
if (data.onSuccess) {
data.onSuccess(parseJSONFromData2(bytes));
} else {
qWarning() << "data.onSuccess not found";
}
reply->deleteLater(); reply->deleteLater();
} else { } else {

View file

@ -811,29 +811,12 @@ void ChannelView::mouseMoveEvent(QMouseEvent *event)
void ChannelView::mousePressEvent(QMouseEvent *event) void ChannelView::mousePressEvent(QMouseEvent *event)
{ {
if (event->modifiers() & (Qt::AltModifier | Qt::ControlModifier)) {
this->unsetCursor();
event->ignore();
return;
}
auto app = getApp(); auto app = getApp();
if (app->settings->linksDoubleClickOnly.getValue()) {
this->pause(200);
}
this->isMouseDown = true;
this->lastPressPosition = event->screenPos();
std::shared_ptr<messages::MessageLayout> layout; std::shared_ptr<messages::MessageLayout> layout;
QPoint relativePos; QPoint relativePos;
int messageIndex; int messageIndex;
this->mouseDown.invoke(event);
if (!tryGetMessageAt(event->pos(), layout, relativePos, messageIndex)) { if (!tryGetMessageAt(event->pos(), layout, relativePos, messageIndex)) {
setCursor(Qt::ArrowCursor); setCursor(Qt::ArrowCursor);
@ -843,14 +826,16 @@ void ChannelView::mousePressEvent(QMouseEvent *event)
} }
// Start selection at the last message at its last index // Start selection at the last message at its last index
auto lastMessageIndex = messagesSnapshot.getLength() - 1; if (event->button() == Qt::LeftButton) {
auto lastMessage = messagesSnapshot[lastMessageIndex]; auto lastMessageIndex = messagesSnapshot.getLength() - 1;
auto lastCharacterIndex = lastMessage->getLastCharacterIndex(); auto lastMessage = messagesSnapshot[lastMessageIndex];
auto lastCharacterIndex = lastMessage->getLastCharacterIndex();
SelectionItem selectionItem(lastMessageIndex, lastCharacterIndex); SelectionItem selectionItem(lastMessageIndex, lastCharacterIndex);
this->setSelection(selectionItem, selectionItem); this->setSelection(selectionItem, selectionItem);
return; return;
}
} }
// check if message is collapsed // check if message is collapsed
@ -858,62 +843,72 @@ void ChannelView::mousePressEvent(QMouseEvent *event)
return; return;
} }
int index = layout->getSelectionIndex(relativePos); switch (event->button()) {
case Qt::LeftButton: {
if (app->settings->linksDoubleClickOnly.getValue()) {
this->pause(200);
}
auto selectionItem = SelectionItem(messageIndex, index); this->lastPressPosition = event->screenPos();
this->setSelection(selectionItem, selectionItem); this->isMouseDown = true;
this->repaint(); int index = layout->getSelectionIndex(relativePos);
auto selectionItem = SelectionItem(messageIndex, index);
this->setSelection(selectionItem, selectionItem);
this->mouseDown.invoke(event);
} break;
case Qt::RightButton: {
this->lastRightPressPosition = event->screenPos();
this->isRightMouseDown = true;
} break;
default:;
}
this->update();
} }
void ChannelView::mouseReleaseEvent(QMouseEvent *event) void ChannelView::mouseReleaseEvent(QMouseEvent *event)
{ {
if (event->modifiers() & (Qt::AltModifier | Qt::ControlModifier)) { // check if mouse was pressed
this->unsetCursor(); if (event->button() == Qt::LeftButton) {
if (this->isMouseDown) {
this->isMouseDown = false;
event->ignore(); if (fabsf(util::distanceBetweenPoints(this->lastPressPosition, event->screenPos())) >
return; 15.f) {
} return;
}
if (!this->isMouseDown) { } else {
// We didn't grab the mouse press, so we shouldn't be handling the mouse return;
// release
return;
}
auto app = getApp();
if (this->selecting) {
if (this->messagesAddedSinceSelectionPause > SELECTION_RESUME_SCROLLING_MSG_THRESHOLD) {
this->showingLatestMessages = false;
} }
} else if (event->button() == Qt::RightButton) {
if (this->isRightMouseDown) {
this->isRightMouseDown = false;
this->pausedBySelection = false; if (fabsf(util::distanceBetweenPoints(this->lastRightPressPosition,
this->selecting = false; event->screenPos())) > 15.f) {
this->pauseTimeout.stop(); return;
this->pausedTemporarily = false; }
} else {
this->layoutMessages(); return;
} }
} else {
this->isMouseDown = false; // not left or right button
float distance = util::distanceBetweenPoints(this->lastPressPosition, event->screenPos());
if (fabsf(distance) > 15.f) {
// It wasn't a proper click, so we don't care about that here
return; return;
} }
// If you clicked and released less than X pixels away, it counts // find message
// as a click!
this->layoutMessages(); this->layoutMessages();
std::shared_ptr<messages::MessageLayout> layout; std::shared_ptr<messages::MessageLayout> layout;
QPoint relativePos; QPoint relativePos;
int messageIndex; int messageIndex;
// no message found
if (!tryGetMessageAt(event->pos(), layout, relativePos, messageIndex)) { if (!tryGetMessageAt(event->pos(), layout, relativePos, messageIndex)) {
// No message at clicked position // No message at clicked position
this->userPopupWidget.hide(); this->userPopupWidget.hide();
@ -935,92 +930,130 @@ void ChannelView::mouseReleaseEvent(QMouseEvent *event)
return; return;
} }
const auto &creator = hoverLayoutElement->getCreator(); // handle the click
this->handleMouseClick(event, hoverLayoutElement, layout.get());
}
void ChannelView::handleMouseClick(QMouseEvent *event,
const messages::MessageLayoutElement *hoveredElement,
messages::MessageLayout *layout)
{
switch (event->button()) {
case Qt::LeftButton: {
if (this->selecting) {
if (this->messagesAddedSinceSelectionPause >
SELECTION_RESUME_SCROLLING_MSG_THRESHOLD) {
this->showingLatestMessages = false;
}
this->pausedBySelection = false;
this->selecting = false;
this->pauseTimeout.stop();
this->pausedTemporarily = false;
this->layoutMessages();
}
auto &link = hoveredElement->getLink();
if (!getApp()->settings->linksDoubleClickOnly) {
this->handleLinkClick(event, link, layout);
this->linkClicked.invoke(link);
}
} break;
case Qt::RightButton: {
this->addContextMenuItems(hoveredElement, layout);
} break;
default:;
}
}
void ChannelView::addContextMenuItems(const messages::MessageLayoutElement *hoveredElement,
messages::MessageLayout *layout)
{
const auto &creator = hoveredElement->getCreator();
auto creatorFlags = creator.getFlags(); auto creatorFlags = creator.getFlags();
if (event->button() == Qt::RightButton) { static QMenu *menu = new QMenu;
static QMenu *menu = new QMenu; menu->clear();
menu->clear();
// Emote actions // Emote actions
if ((creatorFlags & if (creatorFlags & (MessageElement::Flags::EmoteImages | MessageElement::Flags::EmojiImage)) {
(MessageElement::Flags::EmoteImages | MessageElement::Flags::EmojiImage)) != 0) { const auto &emoteElement = static_cast<const messages::EmoteElement &>(creator);
const auto &emoteElement = static_cast<const messages::EmoteElement &>(creator);
// TODO: We might want to add direct "Open image" variants alongside the Copy actions // TODO: We might want to add direct "Open image" variants alongside the Copy
// actions
if (emoteElement.data.image1x != nullptr) { if (emoteElement.data.image1x != nullptr) {
menu->addAction("Copy 1x link", [url = emoteElement.data.image1x->getUrl()] { menu->addAction("Copy 1x link", [url = emoteElement.data.image1x->getUrl()] {
QApplication::clipboard()->setText(url); // QApplication::clipboard()->setText(url); //
}); });
} }
if (emoteElement.data.image2x != nullptr) { if (emoteElement.data.image2x != nullptr) {
menu->addAction("Copy 2x link", [url = emoteElement.data.image2x->getUrl()] { menu->addAction("Copy 2x link", [url = emoteElement.data.image2x->getUrl()] {
QApplication::clipboard()->setText(url); // QApplication::clipboard()->setText(url); //
}); });
} }
if (emoteElement.data.image3x != nullptr) { if (emoteElement.data.image3x != nullptr) {
menu->addAction("Copy 3x link", [url = emoteElement.data.image3x->getUrl()] { menu->addAction("Copy 3x link", [url = emoteElement.data.image3x->getUrl()] {
QApplication::clipboard()->setText(url); // QApplication::clipboard()->setText(url); //
}); });
}
if ((creatorFlags & MessageElement::Flags::BttvEmote) != 0) {
menu->addSeparator();
QString emotePageLink = emoteElement.data.pageLink;
menu->addAction("Copy BTTV emote link", [emotePageLink] {
QApplication::clipboard()->setText(emotePageLink); //
});
} else if ((creatorFlags & MessageElement::Flags::FfzEmote) != 0) {
menu->addSeparator();
QString emotePageLink = emoteElement.data.pageLink;
menu->addAction("Copy FFZ emote link", [emotePageLink] {
QApplication::clipboard()->setText(emotePageLink); //
});
}
} }
// add seperator if ((creatorFlags & MessageElement::Flags::BttvEmote) != 0) {
if (!menu->actions().empty())
menu->addSeparator(); menu->addSeparator();
QString emotePageLink = emoteElement.data.pageLink;
// Link copy menu->addAction("Copy BTTV emote link", [emotePageLink] {
if (hoverLayoutElement->getLink().type == Link::Url) { QApplication::clipboard()->setText(emotePageLink); //
QString url = hoverLayoutElement->getLink().value; });
} else if ((creatorFlags & MessageElement::Flags::FfzEmote) != 0) {
menu->addAction("Open link in browser",
[url] { QDesktopServices::openUrl(QUrl(url)); });
menu->addAction("Copy link", [url] { QApplication::clipboard()->setText(url); });
menu->addSeparator(); menu->addSeparator();
QString emotePageLink = emoteElement.data.pageLink;
menu->addAction("Copy FFZ emote link", [emotePageLink] {
QApplication::clipboard()->setText(emotePageLink); //
});
} }
}
// Message actions // add seperator
if (!menu->actions().empty()) {
menu->addSeparator();
}
// Link copy
if (hoveredElement->getLink().type == Link::Url) {
QString url = hoveredElement->getLink().value;
menu->addAction("Open link in browser", [url] { QDesktopServices::openUrl(QUrl(url)); });
menu->addAction("Copy link", [url] { QApplication::clipboard()->setText(url); });
menu->addSeparator();
}
// Copy actions
menu->addAction("Copy selection",
[this] { QGuiApplication::clipboard()->setText(this->getSelectedText()); });
if (!this->selection.isEmpty()) {
menu->addAction("Copy message", [layout] { menu->addAction("Copy message", [layout] {
QString copyString; QString copyString;
layout->addSelectionText(copyString); layout->addSelectionText(copyString);
QGuiApplication::clipboard()->setText(copyString); QGuiApplication::clipboard()->setText(copyString);
}); });
// menu->addAction("Quote message", [layout] {
// QString copyString;
// layout->addSelectionText(copyString);
// // insert into input
// });
menu->move(QCursor::pos());
menu->show();
return;
} }
auto &link = hoverLayoutElement->getLink(); // menu->addAction("Quote message", [layout] {
if (event->button() != Qt::LeftButton || !app->settings->linksDoubleClickOnly) { // QString copyString;
this->handleLinkClick(event, link, layout.get()); // layout->addSelectionText(copyString);
}
this->linkClicked.invoke(link); // // insert into input
// });
menu->move(QCursor::pos());
menu->show();
return;
} }
void ChannelView::mouseDoubleClickEvent(QMouseEvent *event) void ChannelView::mouseDoubleClickEvent(QMouseEvent *event)

View file

@ -105,6 +105,12 @@ private:
messages::MessageElement::Flags getFlags() const; messages::MessageElement::Flags getFlags() const;
bool isPaused(); bool isPaused();
void handleMouseClick(QMouseEvent *event,
const messages::MessageLayoutElement *hoverLayoutElement,
messages::MessageLayout *layout);
void addContextMenuItems(const messages::MessageLayoutElement *hoveredElement,
messages::MessageLayout *layout);
// void beginPause(); // void beginPause();
// void endPause(); // void endPause();
@ -123,7 +129,9 @@ private:
// Mouse event variables // Mouse event variables
bool isMouseDown = false; bool isMouseDown = false;
bool isRightMouseDown = false;
QPointF lastPressPosition; QPointF lastPressPosition;
QPointF lastRightPressPosition;
messages::Selection selection; messages::Selection selection;
bool selecting = false; bool selecting = false;

View file

@ -237,12 +237,16 @@ void NotebookTab::paintEvent(QPaintEvent *)
: (windowFocused ? colors.backgrounds.regular : (windowFocused ? colors.backgrounds.regular
: colors.backgrounds.unfocused); : colors.backgrounds.unfocused);
painter.fillRect(rect(), this->mouseOver_ ? regular.backgrounds.hover // painter.fillRect(rect(), this->mouseOver_ ? regular.backgrounds.hover
: (windowFocused ? regular.backgrounds.regular // : (windowFocused ? regular.backgrounds.regular
: regular.backgrounds.unfocused)); // :
// regular.backgrounds.unfocused));
// fill the tab background // fill the tab background
painter.fillRect(rect(), tabBackground); auto bgRect = rect();
bgRect.setTop(bgRect.top() + 2);
painter.fillRect(bgRect, tabBackground);
// draw border // draw border
// painter.setPen(QPen("#fff")); // painter.setPen(QPen("#fff"));

View file

@ -50,8 +50,14 @@ AppearancePage::AppearancePage()
{ {
auto form = application.emplace<QFormLayout>(); auto form = application.emplace<QFormLayout>();
auto *theme = this->createComboBox({THEME_ITEMS}, app->themes->themeName);
QObject::connect(theme, &QComboBox::currentTextChanged, [](const QString &) {
getApp()->fonts->incGeneration();
getApp()->windows->repaintVisibleChatWidgets();
});
// clang-format off // clang-format off
form->addRow("Theme:", this->createComboBox({THEME_ITEMS}, app->themes->themeName)); form->addRow("Theme:", theme);
// form->addRow("Theme color:", this->createThemeColorChanger()); // form->addRow("Theme color:", this->createThemeColorChanger());
form->addRow("Font:", this->createFontChanger()); form->addRow("Font:", this->createFontChanger());