mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-13 19:49:51 +01:00
added rightclicking selections to copy them
This commit is contained in:
parent
2299030deb
commit
829809b0e1
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
Loading…
Reference in a new issue