From 829809b0e1863cdd356e110962c578a6631aed2a Mon Sep 17 00:00:00 2001 From: fourtf Date: Mon, 4 Jun 2018 14:39:26 +0200 Subject: [PATCH] added rightclicking selections to copy them --- src/util/networkrequest.hpp | 50 ++-- src/widgets/helper/channelview.cpp | 287 +++++++++++-------- src/widgets/helper/channelview.hpp | 8 + src/widgets/helper/notebooktab.cpp | 12 +- src/widgets/settingspages/appearancepage.cpp | 8 +- 5 files changed, 210 insertions(+), 155 deletions(-) diff --git a/src/util/networkrequest.hpp b/src/util/networkrequest.hpp index ee3cfdf6d..11d8371aa 100644 --- a/src/util/networkrequest.hpp +++ b/src/util/networkrequest.hpp @@ -216,7 +216,7 @@ public: if (this->data.caller != nullptr) { 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) { // TODO: We might want to call an onError callback here return; @@ -238,7 +238,7 @@ public: QObject::connect( &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); if (timer != nullptr) { @@ -253,21 +253,21 @@ public: data.onReplyCreated(reply); } - QObject::connect(reply, &QNetworkReply::finished, worker, [ - data = std::move(data), worker, reply, onFinished = std::move(onFinished) - ]() mutable { - if (data.caller == nullptr) { - QByteArray bytes = reply->readAll(); - data.writeToCache(bytes); - onFinished(bytes); + QObject::connect(reply, &QNetworkReply::finished, worker, + [data = std::move(data), worker, reply, + onFinished = std::move(onFinished)]() mutable { + if (data.caller == nullptr) { + QByteArray bytes = reply->readAll(); + data.writeToCache(bytes); + onFinished(bytes); - reply->deleteLater(); - } else { - emit worker->doneUrl(reply); - } + reply->deleteLater(); + } else { + emit worker->doneUrl(reply); + } - delete worker; - }); + delete worker; + }); }); emit requester.requestUrl(); @@ -276,8 +276,7 @@ public: template 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); onFinished(object); @@ -290,7 +289,7 @@ public: template 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); onFinished(object); @@ -371,8 +370,8 @@ private: worker->moveToThread(&NetworkManager::workerThread); if (this->data.caller != nullptr) { - QObject::connect(worker, &NetworkWorker::doneUrl, - this->data.caller, [data = this->data](auto reply) mutable { + QObject::connect(worker, &NetworkWorker::doneUrl, this->data.caller, + [data = this->data](auto reply) mutable { if (reply->error() != QNetworkReply::NetworkError::NoError) { if (data.onError) { data.onError(reply->error()); @@ -395,7 +394,7 @@ private: } QObject::connect(&requester, &NetworkRequester::requestUrl, worker, - [ timer, data = std::move(this->data), worker ]() { + [timer, data = std::move(this->data), worker]() { QNetworkReply *reply = nullptr; switch (data.requestType) { case GetRequest: { @@ -431,11 +430,16 @@ private: } QObject::connect(reply, &QNetworkReply::finished, worker, - [ data = std::move(data), worker, reply ]() mutable { + [data = std::move(data), worker, reply]() mutable { if (data.caller == nullptr) { QByteArray bytes = reply->readAll(); data.writeToCache(bytes); -// data.onSuccess(parseJSONFromData2(bytes)); + + if (data.onSuccess) { + data.onSuccess(parseJSONFromData2(bytes)); + } else { + qWarning() << "data.onSuccess not found"; + } reply->deleteLater(); } else { diff --git a/src/widgets/helper/channelview.cpp b/src/widgets/helper/channelview.cpp index 6b461e65a..9d06843f6 100644 --- a/src/widgets/helper/channelview.cpp +++ b/src/widgets/helper/channelview.cpp @@ -811,29 +811,12 @@ void ChannelView::mouseMoveEvent(QMouseEvent *event) void ChannelView::mousePressEvent(QMouseEvent *event) { - if (event->modifiers() & (Qt::AltModifier | Qt::ControlModifier)) { - this->unsetCursor(); - - event->ignore(); - return; - } - auto app = getApp(); - if (app->settings->linksDoubleClickOnly.getValue()) { - this->pause(200); - } - - this->isMouseDown = true; - - this->lastPressPosition = event->screenPos(); - std::shared_ptr layout; QPoint relativePos; int messageIndex; - this->mouseDown.invoke(event); - if (!tryGetMessageAt(event->pos(), layout, relativePos, messageIndex)) { setCursor(Qt::ArrowCursor); @@ -843,14 +826,16 @@ void ChannelView::mousePressEvent(QMouseEvent *event) } // Start selection at the last message at its last index - auto lastMessageIndex = messagesSnapshot.getLength() - 1; - auto lastMessage = messagesSnapshot[lastMessageIndex]; - auto lastCharacterIndex = lastMessage->getLastCharacterIndex(); + if (event->button() == Qt::LeftButton) { + auto lastMessageIndex = messagesSnapshot.getLength() - 1; + auto lastMessage = messagesSnapshot[lastMessageIndex]; + auto lastCharacterIndex = lastMessage->getLastCharacterIndex(); - SelectionItem selectionItem(lastMessageIndex, lastCharacterIndex); - this->setSelection(selectionItem, selectionItem); + SelectionItem selectionItem(lastMessageIndex, lastCharacterIndex); + this->setSelection(selectionItem, selectionItem); - return; + return; + } } // check if message is collapsed @@ -858,62 +843,72 @@ void ChannelView::mousePressEvent(QMouseEvent *event) 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->setSelection(selectionItem, selectionItem); + this->lastPressPosition = event->screenPos(); + 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) { - if (event->modifiers() & (Qt::AltModifier | Qt::ControlModifier)) { - this->unsetCursor(); + // check if mouse was pressed + if (event->button() == Qt::LeftButton) { + if (this->isMouseDown) { + this->isMouseDown = false; - event->ignore(); - return; - } - - if (!this->isMouseDown) { - // We didn't grab the mouse press, so we shouldn't be handling the mouse - // release - return; - } - - auto app = getApp(); - - if (this->selecting) { - if (this->messagesAddedSinceSelectionPause > SELECTION_RESUME_SCROLLING_MSG_THRESHOLD) { - this->showingLatestMessages = false; + if (fabsf(util::distanceBetweenPoints(this->lastPressPosition, event->screenPos())) > + 15.f) { + return; + } + } else { + return; } + } else if (event->button() == Qt::RightButton) { + if (this->isRightMouseDown) { + this->isRightMouseDown = false; - this->pausedBySelection = false; - this->selecting = false; - this->pauseTimeout.stop(); - this->pausedTemporarily = false; - - this->layoutMessages(); - } - - this->isMouseDown = false; - - 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 + if (fabsf(util::distanceBetweenPoints(this->lastRightPressPosition, + event->screenPos())) > 15.f) { + return; + } + } else { + return; + } + } else { + // not left or right button return; } - // If you clicked and released less than X pixels away, it counts - // as a click! - + // find message this->layoutMessages(); std::shared_ptr layout; QPoint relativePos; int messageIndex; + // no message found if (!tryGetMessageAt(event->pos(), layout, relativePos, messageIndex)) { // No message at clicked position this->userPopupWidget.hide(); @@ -935,92 +930,130 @@ void ChannelView::mouseReleaseEvent(QMouseEvent *event) 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(); - if (event->button() == Qt::RightButton) { - static QMenu *menu = new QMenu; - menu->clear(); + static QMenu *menu = new QMenu; + menu->clear(); - // Emote actions - if ((creatorFlags & - (MessageElement::Flags::EmoteImages | MessageElement::Flags::EmojiImage)) != 0) { - const auto &emoteElement = static_cast(creator); + // Emote actions + if (creatorFlags & (MessageElement::Flags::EmoteImages | MessageElement::Flags::EmojiImage)) { + const auto &emoteElement = static_cast(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) { - menu->addAction("Copy 1x link", [url = emoteElement.data.image1x->getUrl()] { - QApplication::clipboard()->setText(url); // - }); - } - if (emoteElement.data.image2x != nullptr) { - menu->addAction("Copy 2x link", [url = emoteElement.data.image2x->getUrl()] { - QApplication::clipboard()->setText(url); // - }); - } - if (emoteElement.data.image3x != nullptr) { - menu->addAction("Copy 3x link", [url = emoteElement.data.image3x->getUrl()] { - 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); // - }); - } + if (emoteElement.data.image1x != nullptr) { + menu->addAction("Copy 1x link", [url = emoteElement.data.image1x->getUrl()] { + QApplication::clipboard()->setText(url); // + }); + } + if (emoteElement.data.image2x != nullptr) { + menu->addAction("Copy 2x link", [url = emoteElement.data.image2x->getUrl()] { + QApplication::clipboard()->setText(url); // + }); + } + if (emoteElement.data.image3x != nullptr) { + menu->addAction("Copy 3x link", [url = emoteElement.data.image3x->getUrl()] { + QApplication::clipboard()->setText(url); // + }); } - // add seperator - if (!menu->actions().empty()) + if ((creatorFlags & MessageElement::Flags::BttvEmote) != 0) { menu->addSeparator(); - - // Link copy - if (hoverLayoutElement->getLink().type == Link::Url) { - QString url = hoverLayoutElement->getLink().value; - - menu->addAction("Open link in browser", - [url] { QDesktopServices::openUrl(QUrl(url)); }); - menu->addAction("Copy link", [url] { QApplication::clipboard()->setText(url); }); - + 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); // + }); } + } - // 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] { QString copyString; layout->addSelectionText(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(); - if (event->button() != Qt::LeftButton || !app->settings->linksDoubleClickOnly) { - this->handleLinkClick(event, link, layout.get()); - } + // menu->addAction("Quote message", [layout] { + // QString copyString; + // layout->addSelectionText(copyString); - this->linkClicked.invoke(link); + // // insert into input + // }); + + menu->move(QCursor::pos()); + menu->show(); + + return; } void ChannelView::mouseDoubleClickEvent(QMouseEvent *event) diff --git a/src/widgets/helper/channelview.hpp b/src/widgets/helper/channelview.hpp index 98f028d9a..db74aa2bb 100644 --- a/src/widgets/helper/channelview.hpp +++ b/src/widgets/helper/channelview.hpp @@ -105,6 +105,12 @@ private: messages::MessageElement::Flags getFlags() const; 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 endPause(); @@ -123,7 +129,9 @@ private: // Mouse event variables bool isMouseDown = false; + bool isRightMouseDown = false; QPointF lastPressPosition; + QPointF lastRightPressPosition; messages::Selection selection; bool selecting = false; diff --git a/src/widgets/helper/notebooktab.cpp b/src/widgets/helper/notebooktab.cpp index 880fe3010..3c89639cc 100644 --- a/src/widgets/helper/notebooktab.cpp +++ b/src/widgets/helper/notebooktab.cpp @@ -237,12 +237,16 @@ void NotebookTab::paintEvent(QPaintEvent *) : (windowFocused ? colors.backgrounds.regular : colors.backgrounds.unfocused); - painter.fillRect(rect(), this->mouseOver_ ? regular.backgrounds.hover - : (windowFocused ? regular.backgrounds.regular - : regular.backgrounds.unfocused)); + // painter.fillRect(rect(), this->mouseOver_ ? regular.backgrounds.hover + // : (windowFocused ? regular.backgrounds.regular + // : + // regular.backgrounds.unfocused)); // fill the tab background - painter.fillRect(rect(), tabBackground); + auto bgRect = rect(); + bgRect.setTop(bgRect.top() + 2); + + painter.fillRect(bgRect, tabBackground); // draw border // painter.setPen(QPen("#fff")); diff --git a/src/widgets/settingspages/appearancepage.cpp b/src/widgets/settingspages/appearancepage.cpp index 1b4472da2..c94264d15 100644 --- a/src/widgets/settingspages/appearancepage.cpp +++ b/src/widgets/settingspages/appearancepage.cpp @@ -50,8 +50,14 @@ AppearancePage::AppearancePage() { auto form = application.emplace(); + 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 - form->addRow("Theme:", this->createComboBox({THEME_ITEMS}, app->themes->themeName)); + form->addRow("Theme:", theme); // form->addRow("Theme color:", this->createThemeColorChanger()); form->addRow("Font:", this->createFontChanger());