mirror of https://github.com/qTox/qTox.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
264 lines
7.8 KiB
264 lines
7.8 KiB
/* |
|
Copyright © 2015-2019 by The qTox Project Contributors |
|
|
|
This file is part of qTox, a Qt-based graphical interface for Tox. |
|
|
|
qTox is libre software: you can redistribute it and/or modify |
|
it under the terms of the GNU General Public License as published by |
|
the Free Software Foundation, either version 3 of the License, or |
|
(at your option) any later version. |
|
|
|
qTox is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
GNU General Public License for more details. |
|
|
|
You should have received a copy of the GNU General Public License |
|
along with qTox. If not, see <http://www.gnu.org/licenses/>. |
|
*/ |
|
|
|
#include "screenshotgrabber.h" |
|
|
|
#include <QApplication> |
|
#include <QDebug> |
|
#include <QDesktopWidget> |
|
#include <QGraphicsPixmapItem> |
|
#include <QGraphicsRectItem> |
|
#include <QGraphicsSceneMouseEvent> |
|
#include <QGraphicsView> |
|
#include <QMouseEvent> |
|
#include <QScreen> |
|
#include <QTimer> |
|
|
|
#include "screengrabberchooserrectitem.h" |
|
#include "screengrabberoverlayitem.h" |
|
#include "toolboxgraphicsitem.h" |
|
#include "src/widget/widget.h" |
|
|
|
ScreenshotGrabber::ScreenshotGrabber() |
|
: QObject() |
|
, mKeysBlocked(false) |
|
, scene(nullptr) |
|
, mQToxVisible(true) |
|
{ |
|
window = new QGraphicsView(scene); // Top-level widget |
|
window->setWindowFlags(Qt::FramelessWindowHint | Qt::BypassWindowManagerHint); |
|
window->setContentsMargins(0, 0, 0, 0); |
|
window->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); |
|
window->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); |
|
window->setFrameShape(QFrame::NoFrame); |
|
window->installEventFilter(this); |
|
pixRatio = QApplication::primaryScreen()->devicePixelRatio(); |
|
|
|
setupScene(); |
|
} |
|
|
|
void ScreenshotGrabber::reInit() |
|
{ |
|
window->resetCachedContent(); |
|
setupScene(); |
|
showGrabber(); |
|
mKeysBlocked = false; |
|
} |
|
|
|
ScreenshotGrabber::~ScreenshotGrabber() |
|
{ |
|
delete scene; |
|
delete window; |
|
} |
|
|
|
bool ScreenshotGrabber::eventFilter(QObject* object, QEvent* event) |
|
{ |
|
if (event->type() == QEvent::KeyPress) |
|
return handleKeyPress(static_cast<QKeyEvent*>(event)); |
|
|
|
return QObject::eventFilter(object, event); |
|
} |
|
|
|
void ScreenshotGrabber::showGrabber() |
|
{ |
|
this->screenGrab = grabScreen(); |
|
this->screenGrabDisplay->setPixmap(this->screenGrab); |
|
this->window->show(); |
|
this->window->setFocus(); |
|
this->window->grabKeyboard(); |
|
|
|
QRect fullGrabbedRect = screenGrab.rect(); |
|
QRect rec = QApplication::primaryScreen()->virtualGeometry(); |
|
|
|
this->window->setGeometry(rec); |
|
this->scene->setSceneRect(fullGrabbedRect); |
|
this->overlay->setRect(fullGrabbedRect); |
|
|
|
adjustTooltipPosition(); |
|
} |
|
|
|
bool ScreenshotGrabber::handleKeyPress(QKeyEvent* event) |
|
{ |
|
if (mKeysBlocked) |
|
return false; |
|
|
|
if (event->key() == Qt::Key_Escape) |
|
reject(); |
|
else if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) |
|
acceptRegion(); |
|
else if (event->key() == Qt::Key_Space) { |
|
mKeysBlocked = true; |
|
|
|
if (mQToxVisible) |
|
hideVisibleWindows(); |
|
else |
|
restoreHiddenWindows(); |
|
|
|
window->hide(); |
|
QTimer::singleShot(350, this, SLOT(reInit())); |
|
} else |
|
return false; |
|
|
|
return true; |
|
} |
|
|
|
void ScreenshotGrabber::acceptRegion() |
|
{ |
|
QRect rect = this->chooserRect->chosenRect(); |
|
if (rect.width() < 1 || rect.height() < 1) |
|
return; |
|
|
|
// Scale the accepted region from DIPs to actual pixels |
|
rect.setRect(rect.x() * pixRatio, rect.y() * pixRatio, rect.width() * pixRatio, |
|
rect.height() * pixRatio); |
|
|
|
emit regionChosen(rect); |
|
qDebug() << "Screenshot accepted, chosen region" << rect; |
|
QPixmap pixmap = this->screenGrab.copy(rect); |
|
restoreHiddenWindows(); |
|
emit screenshotTaken(pixmap); |
|
|
|
deleteLater(); |
|
} |
|
|
|
void ScreenshotGrabber::setupScene() |
|
{ |
|
delete scene; |
|
scene = new QGraphicsScene; |
|
window->setScene(scene); |
|
|
|
this->overlay = new ScreenGrabberOverlayItem(this); |
|
this->helperToolbox = new ToolBoxGraphicsItem; |
|
|
|
this->screenGrabDisplay = scene->addPixmap(this->screenGrab); |
|
this->helperTooltip = scene->addText(QString()); |
|
|
|
scene->addItem(this->overlay); |
|
this->chooserRect = new ScreenGrabberChooserRectItem(scene); |
|
scene->addItem(this->helperToolbox); |
|
|
|
this->helperToolbox->addToGroup(this->helperTooltip); |
|
this->helperTooltip->setDefaultTextColor(Qt::black); |
|
useNothingSelectedTooltip(); |
|
|
|
connect(this->chooserRect, &ScreenGrabberChooserRectItem::doubleClicked, this, |
|
&ScreenshotGrabber::acceptRegion); |
|
connect(this->chooserRect, &ScreenGrabberChooserRectItem::regionChosen, this, |
|
&ScreenshotGrabber::chooseHelperTooltipText); |
|
connect(this->chooserRect, &ScreenGrabberChooserRectItem::regionChosen, this->overlay, |
|
&ScreenGrabberOverlayItem::setChosenRect); |
|
} |
|
|
|
void ScreenshotGrabber::useNothingSelectedTooltip() |
|
{ |
|
helperTooltip->setHtml( |
|
tr("Click and drag to select a region. Press %1 to " |
|
"hide/show qTox window, or %2 to cancel.", |
|
"Help text shown when no region has been selected yet") |
|
.arg(QString("<b>%1</b>").arg(tr("Space", "[Space] key on the keyboard")), |
|
QString("<b>%1</b>").arg(tr("Escape", "[Escape] key on the keyboard")))); |
|
adjustTooltipPosition(); |
|
} |
|
|
|
void ScreenshotGrabber::useRegionSelectedTooltip() |
|
{ |
|
helperTooltip->setHtml( |
|
tr("Press %1 to send a screenshot of the selection, " |
|
"%2 to hide/show qTox window, or %3 to cancel.", |
|
"Help text shown when a region has been selected") |
|
.arg(QString("<b>%1</b>").arg(tr("Enter", "[Enter] key on the keyboard")), |
|
QString("<b>%1</b>").arg(tr("Space", "[Space] key on the keyboard")), |
|
QString("<b>%1</b>").arg(tr("Escape", "[Escape] key on the keyboard")))); |
|
adjustTooltipPosition(); |
|
} |
|
|
|
void ScreenshotGrabber::chooseHelperTooltipText(QRect rect) |
|
{ |
|
if (rect.size().isNull()) |
|
useNothingSelectedTooltip(); |
|
else |
|
useRegionSelectedTooltip(); |
|
} |
|
|
|
/** |
|
* @internal |
|
* @brief Align the tooltip centered at top of screen with the mouse cursor. |
|
*/ |
|
void ScreenshotGrabber::adjustTooltipPosition() |
|
{ |
|
QRect recGL = QGuiApplication::primaryScreen()->virtualGeometry(); |
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) |
|
const auto rec = QGuiApplication::screenAt(QCursor::pos())->geometry(); |
|
#else |
|
const auto rec = qApp->desktop()->screenGeometry(QCursor::pos()); |
|
#endif |
|
const QRectF ttRect = this->helperToolbox->childrenBoundingRect(); |
|
int x = qAbs(recGL.x()) + rec.x() + ((rec.width() - ttRect.width()) / 2); |
|
int y = qAbs(recGL.y()) + rec.y(); |
|
|
|
helperToolbox->setX(x); |
|
helperToolbox->setY(y); |
|
} |
|
|
|
void ScreenshotGrabber::reject() |
|
{ |
|
restoreHiddenWindows(); |
|
deleteLater(); |
|
} |
|
|
|
QPixmap ScreenshotGrabber::grabScreen() |
|
{ |
|
QScreen* screen = QGuiApplication::primaryScreen(); |
|
QRect rec = screen->virtualGeometry(); |
|
|
|
// Multiply by devicePixelRatio to get actual desktop size |
|
return screen->grabWindow(QApplication::desktop()->winId(), rec.x() * pixRatio, |
|
rec.y() * pixRatio, rec.width() * pixRatio, rec.height() * pixRatio); |
|
} |
|
|
|
void ScreenshotGrabber::hideVisibleWindows() |
|
{ |
|
foreach (QWidget* w, qApp->topLevelWidgets()) { |
|
if (w != window && w->isVisible()) { |
|
mHiddenWindows << w; |
|
w->setVisible(false); |
|
} |
|
} |
|
|
|
mQToxVisible = false; |
|
} |
|
|
|
void ScreenshotGrabber::restoreHiddenWindows() |
|
{ |
|
foreach (QWidget* w, mHiddenWindows) { |
|
if (w) |
|
w->setVisible(true); |
|
} |
|
|
|
mHiddenWindows.clear(); |
|
mQToxVisible = true; |
|
} |
|
|
|
void ScreenshotGrabber::beginRectChooser(QGraphicsSceneMouseEvent* event) |
|
{ |
|
QPointF pos = event->scenePos(); |
|
this->chooserRect->setX(pos.x()); |
|
this->chooserRect->setY(pos.y()); |
|
this->chooserRect->beginResize(event->scenePos()); |
|
}
|
|
|