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) {
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 <typename FinishedCallback>
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 <typename FinishedCallback>
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 {

View file

@ -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<messages::MessageLayout> 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<messages::MessageLayout> 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<const messages::EmoteElement &>(creator);
// Emote actions
if (creatorFlags & (MessageElement::Flags::EmoteImages | MessageElement::Flags::EmojiImage)) {
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) {
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)

View file

@ -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;

View file

@ -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"));

View file

@ -50,8 +50,14 @@ AppearancePage::AppearancePage()
{
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
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());