Commit 4a3cb514 authored by Méven Car's avatar Méven Car Committed by Nate Graham
Browse files

Support Wayland rectangular selection HiDpi

When the drawn rectangle is on a single screen, the output image uses the screen native resolution.
When the drawn rectangle is on screens with multiple scale factor, the output image is upscaled to correspond to the screen with the hightest scale factor to keep the image undistorted.

Adds also a "scaled" full screen mode, to capture screens content downscaled to screens virtualsize allowing for undistorted content albeit loosing details.

Requires Plasma 5.19.80+

BUG: 409762
BUG: 420863
FIXED-IN: 20.12
parent b79ac774
...@@ -63,22 +63,30 @@ KSWidget::KSWidget(Platform::GrabModes theGrabModes, QWidget *parent) ...@@ -63,22 +63,30 @@ KSWidget::KSWidget(Platform::GrabModes theGrabModes, QWidget *parent)
// the capture mode options first // the capture mode options first
mCaptureModeLabel = new QLabel(i18n("<b>Capture Mode</b>"), this); mCaptureModeLabel = new QLabel(i18n("<b>Capture Mode</b>"), this);
mCaptureArea = new QComboBox(this); mCaptureArea = new QComboBox(this);
if (theGrabModes.testFlag(Platform::GrabMode::AllScreens)) {
QString lFullScreenLabel = QApplication::screens().count() == 1 QString lFullScreenLabel = QApplication::screens().count() == 1
? i18n("Full Screen") ? i18n("Full Screen")
: i18n("Full Screen (All Monitors)"); : i18n("Full Screen (All Monitors)");
if (theGrabModes.testFlag(Platform::GrabMode::AllScreens)) {
mCaptureArea->insertItem(0, lFullScreenLabel, Spectacle::CaptureMode::AllScreens); mCaptureArea->insertItem(0, lFullScreenLabel, Spectacle::CaptureMode::AllScreens);
mCaptureArea->insertItem(1, i18n("Rectangular Region"), Spectacle::CaptureMode::RectangularRegion); }
if (theGrabModes.testFlag(Platform::GrabMode::AllScreensScaled) && QApplication::screens().count() > 1) {
QString lFullScreenLabel = i18n("Full Screen (All Monitors, scaled)");
mCaptureArea->insertItem(1, lFullScreenLabel, Spectacle::CaptureMode::AllScreensScaled);
}
if (theGrabModes.testFlag(Platform::GrabMode::PerScreenImageNative)) {
mCaptureArea->insertItem(2, i18n("Rectangular Region"), Spectacle::CaptureMode::RectangularRegion);
} }
if (theGrabModes.testFlag(Platform::GrabMode::CurrentScreen)) { if (theGrabModes.testFlag(Platform::GrabMode::CurrentScreen)) {
mCaptureArea->insertItem(2, i18n("Current Screen"), Spectacle::CaptureMode::CurrentScreen); mCaptureArea->insertItem(3, i18n("Current Screen"), Spectacle::CaptureMode::CurrentScreen);
} }
if (theGrabModes.testFlag(Platform::GrabMode::ActiveWindow)) { if (theGrabModes.testFlag(Platform::GrabMode::ActiveWindow)) {
mCaptureArea->insertItem(3, i18n("Active Window"), Spectacle::CaptureMode::ActiveWindow); mCaptureArea->insertItem(4, i18n("Active Window"), Spectacle::CaptureMode::ActiveWindow);
} }
if (theGrabModes.testFlag(Platform::GrabMode::WindowUnderCursor)) { if (theGrabModes.testFlag(Platform::GrabMode::WindowUnderCursor)) {
mCaptureArea->insertItem(4, i18n("Window Under Cursor"), Spectacle::CaptureMode::WindowUnderCursor); mCaptureArea->insertItem(5, i18n("Window Under Cursor"), Spectacle::CaptureMode::WindowUnderCursor);
} }
if (theGrabModes.testFlag(Platform::GrabMode::TransientWithParent)) { if (theGrabModes.testFlag(Platform::GrabMode::TransientWithParent)) {
mTransientWithParentAvailable = true; mTransientWithParentAvailable = true;
...@@ -225,8 +233,7 @@ void KSWidget::lockOnClickEnabled() ...@@ -225,8 +233,7 @@ void KSWidget::lockOnClickEnabled()
void KSWidget::lockOnClickDisabled() void KSWidget::lockOnClickDisabled()
{ {
mCaptureOnClick->setCheckState(Qt::Unchecked); mCaptureOnClick->hide();
mCaptureOnClick->setEnabled(false);
mDelayMsec->setEnabled(true); mDelayMsec->setEnabled(true);
} }
...@@ -271,6 +278,7 @@ void KSWidget::captureModeChanged(int theIndex) ...@@ -271,6 +278,7 @@ void KSWidget::captureModeChanged(int theIndex)
mCaptureTransientOnly->setEnabled(false); mCaptureTransientOnly->setEnabled(false);
break; break;
case Spectacle::CaptureMode::AllScreens: case Spectacle::CaptureMode::AllScreens:
case Spectacle::CaptureMode::AllScreensScaled:
case Spectacle::CaptureMode::CurrentScreen: case Spectacle::CaptureMode::CurrentScreen:
case Spectacle::CaptureMode::RectangularRegion: case Spectacle::CaptureMode::RectangularRegion:
mWindowDecorations->setEnabled(false); mWindowDecorations->setEnabled(false);
......
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
#include <QObject> #include <QObject>
#include <QFlags> #include <QFlags>
#include "QuickEditor/ComparableQPoint.h"
class Platform: public QObject class Platform: public QObject
{ {
Q_OBJECT Q_OBJECT
...@@ -36,7 +38,9 @@ class Platform: public QObject ...@@ -36,7 +38,9 @@ class Platform: public QObject
CurrentScreen = 0x02, CurrentScreen = 0x02,
ActiveWindow = 0x04, ActiveWindow = 0x04,
WindowUnderCursor = 0x08, WindowUnderCursor = 0x08,
TransientWithParent = 0x10 TransientWithParent = 0x10,
AllScreensScaled = 0x20,
PerScreenImageNative= 0x40,
}; };
using GrabModes = QFlags<GrabMode>; using GrabModes = QFlags<GrabMode>;
Q_FLAG(GrabModes) Q_FLAG(GrabModes)
...@@ -62,6 +66,8 @@ class Platform: public QObject ...@@ -62,6 +66,8 @@ class Platform: public QObject
Q_SIGNALS: Q_SIGNALS:
void newScreenshotTaken(const QPixmap &thePixmap); void newScreenshotTaken(const QPixmap &thePixmap);
void newScreensScreenshotTaken(const QVector<QImage> &images);
void newScreenshotFailed(); void newScreenshotFailed();
void windowTitleChanged(const QString &theWindowTitle); void windowTitleChanged(const QString &theWindowTitle);
}; };
......
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
#include <QDBusUnixFileDescriptor> #include <QDBusUnixFileDescriptor>
#include <QDBusPendingCall> #include <QDBusPendingCall>
#include <QFutureWatcher> #include <QFutureWatcher>
#include <QScreen>
#include <QGuiApplication>
#include <array> #include <array>
...@@ -73,6 +75,30 @@ static QImage readImage(int thePipeFd) ...@@ -73,6 +75,30 @@ static QImage readImage(int thePipeFd)
return lImage; return lImage;
} }
static QVector<QImage> readImages(int thePipeFd)
{
QByteArray lContent;
if (readData(thePipeFd, lContent) != 0) {
close(thePipeFd);
return QVector<QImage>();
}
close(thePipeFd);
QDataStream lDataStream(lContent);
lDataStream.setVersion(QDataStream::Qt_DefaultCompiledVersion);
QImage lImage;
QVector<QImage> imgs;
while (!lDataStream.atEnd()){
lDataStream >> lImage;
if (!lImage.isNull()) {
imgs << lImage;
}
}
return imgs;
}
/* -- General Plumbing ------------------------------------------------------------------------- */ /* -- General Plumbing ------------------------------------------------------------------------- */
PlatformKWinWayland::PlatformKWinWayland(QObject *parent) : PlatformKWinWayland::PlatformKWinWayland(QObject *parent) :
...@@ -84,15 +110,6 @@ QString PlatformKWinWayland::platformName() const ...@@ -84,15 +110,6 @@ QString PlatformKWinWayland::platformName() const
return QStringLiteral("KWinWayland"); return QStringLiteral("KWinWayland");
} }
Platform::GrabModes PlatformKWinWayland::supportedGrabModes() const
{
Platform::GrabModes lSupportedModes({ GrabMode::AllScreens, GrabMode::WindowUnderCursor });
if (QApplication::screens().count() > 1) {
lSupportedModes |= Platform::GrabMode::CurrentScreen;
}
return lSupportedModes;
}
static std::array<int, 3> s_plasmaVersion = {-1, -1, -1}; static std::array<int, 3> s_plasmaVersion = {-1, -1, -1};
std::array<int, 3> findPlasmaMinorVersion () { std::array<int, 3> findPlasmaMinorVersion () {
...@@ -138,22 +155,77 @@ std::array<int, 3> findPlasmaMinorVersion () { ...@@ -138,22 +155,77 @@ std::array<int, 3> findPlasmaMinorVersion () {
return s_plasmaVersion; return s_plasmaVersion;
} }
Platform::GrabModes PlatformKWinWayland::supportedGrabModes() const
{
Platform::GrabModes lSupportedModes({ Platform::GrabMode::AllScreens, GrabMode::WindowUnderCursor });
QList<QScreen *> screens = QApplication::screens();
// TODO remove sometime after Plasma 5.21 is released
// We can handle rectangular selection one one screen not scale factor
// on Plasma < 5.21
if (screenshotScreensAvailable() || (screens.count() == 1 && screens.first()->devicePixelRatio() == 1)) {
lSupportedModes |= Platform::GrabMode::PerScreenImageNative;
}
// TODO remove sometime after Plasma 5.20 is released
auto plasmaVersion = findPlasmaMinorVersion();
if (plasmaVersion.at(0) != -1 && (plasmaVersion.at(0) != 5 || (plasmaVersion.at(1) >= 20))) {
lSupportedModes |= Platform::GrabMode::AllScreensScaled;
}
if (screens.count() > 1) {
lSupportedModes |= Platform::GrabMode::CurrentScreen;
}
return lSupportedModes;
}
bool PlatformKWinWayland::screenshotScreensAvailable() const
{
// TODO remove sometime after Plasma 5.21 is released
auto plasmaVersion = findPlasmaMinorVersion();
// Screenshot screenshotScreens dbus interface requires Plasma 5.21
if (plasmaVersion.at(0) != -1 && (plasmaVersion.at(0) != 5 || (plasmaVersion.at(1) >= 21 || (plasmaVersion.at(1) == 20 && plasmaVersion.at(2) >= 80)))) {
return true;
} else {
return false;
}
}
Platform::ShutterModes PlatformKWinWayland::supportedShutterModes() const Platform::ShutterModes PlatformKWinWayland::supportedShutterModes() const
{ {
// TODO remove sometime after Plasma 5.20 is released // TODO remove sometime after Plasma 5.20 is released
auto plasmaVersion = findPlasmaMinorVersion(); auto plasmaVersion = findPlasmaMinorVersion();
if (plasmaVersion.at(0) != -1 && (plasmaVersion.at(0) != 5 || (plasmaVersion.at(1) >= 20 || (plasmaVersion.at(1) == 19 && plasmaVersion.at(2) >= 80)))) { if (plasmaVersion.at(0) != -1 && (plasmaVersion.at(0) != 5 || (plasmaVersion.at(1) >= 20))) {
return { ShutterMode::Immediate | ShutterMode::OnClick }; return { ShutterMode::Immediate };
} else { } else {
return { ShutterMode::OnClick }; return { ShutterMode::OnClick };
} }
} }
void PlatformKWinWayland::doGrab(ShutterMode theShutterMode, GrabMode theGrabMode, bool theIncludePointer, bool theIncludeDecorations) void PlatformKWinWayland::doGrab(ShutterMode /* theShutterMode */, GrabMode theGrabMode, bool theIncludePointer, bool theIncludeDecorations)
{ {
switch(theGrabMode) { switch(theGrabMode) {
case GrabMode::AllScreens: { case GrabMode::AllScreens:
doGrabHelper(QStringLiteral("screenshotFullscreen"), theIncludePointer); doGrabHelper(QStringLiteral("screenshotFullscreen"), theIncludePointer, true);
return;
case GrabMode::AllScreensScaled:
doGrabHelper(QStringLiteral("screenshotFullscreen"), theIncludePointer, false);
return;
case GrabMode::PerScreenImageNative:
{
QList<QScreen *> screens = QGuiApplication::screens();
QStringList screenNames;
for (const auto screen : screens) {
screenNames << screen->name();
}
if (screenshotScreensAvailable()) {
doGrabImagesHelper(QStringLiteral("screenshotScreens"), screenNames, theIncludePointer, true);
} else {
// TODO remove sometime after Plasma 5.21 is released
// Use the dbus call screenshotFullscreen to get a single screen screenshot and treat it as a list of images
doGrabImagesHelper(QStringLiteral("screenshotFullscreen"), theIncludePointer, true);
}
return; return;
} }
case GrabMode::CurrentScreen: { case GrabMode::CurrentScreen: {
...@@ -185,18 +257,43 @@ void PlatformKWinWayland::startReadImage(int theReadPipe) ...@@ -185,18 +257,43 @@ void PlatformKWinWayland::startReadImage(int theReadPipe)
[lWatcher, this] () { [lWatcher, this] () {
lWatcher->deleteLater(); lWatcher->deleteLater();
const QImage lImage = lWatcher->result(); const QImage lImage = lWatcher->result();
emit newScreenshotTaken(QPixmap::fromImage(lImage)); if (lImage.isNull()) {
newScreenshotFailed();
} else {
newScreenshotTaken(QPixmap::fromImage(lImage));
}
} }
); );
lWatcher->setFuture(QtConcurrent::run(readImage, theReadPipe)); lWatcher->setFuture(QtConcurrent::run(readImage, theReadPipe));
} }
template <typename ArgType> void PlatformKWinWayland::startReadImages(int theReadPipe)
void PlatformKWinWayland::callDBus(const QString &theGrabMethod, ArgType theArgument, int theWriteFile) {
auto lWatcher = new QFutureWatcher<QVector<QImage>>(this);
QObject::connect(lWatcher, &QFutureWatcher<QVector<QImage>>::finished, this,
[lWatcher, this] () {
lWatcher->deleteLater();
auto result = lWatcher->result();
if (result.isEmpty()) {
newScreenshotFailed();
} else {
newScreensScreenshotTaken(result);
}
}
);
lWatcher->setFuture(QtConcurrent::run(readImages, theReadPipe));
}
template <typename ... ArgType>
void PlatformKWinWayland::callDBus(const QString &theGrabMethod, int theWriteFile, ArgType ... arguments)
{ {
QDBusInterface lInterface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Screenshot"), QStringLiteral("org.kde.kwin.Screenshot")); QDBusInterface lInterface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Screenshot"), QStringLiteral("org.kde.kwin.Screenshot"));
QDBusPendingCall pcall = lInterface.asyncCall(theGrabMethod, QVariant::fromValue(QDBusUnixFileDescriptor(theWriteFile)), theArgument); QDBusPendingCall pcall = lInterface.asyncCall(theGrabMethod, QVariant::fromValue(QDBusUnixFileDescriptor(theWriteFile)), arguments...);
checkDbusPendingCall(pcall);
}
void PlatformKWinWayland::checkDbusPendingCall(QDBusPendingCall pcall)
{
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this);
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, QObject::connect(watcher, &QDBusPendingCallWatcher::finished,
this, [this](QDBusPendingCallWatcher* watcher) { this, [this](QDBusPendingCallWatcher* watcher) {
...@@ -209,8 +306,8 @@ void PlatformKWinWayland::callDBus(const QString &theGrabMethod, ArgType theArgu ...@@ -209,8 +306,8 @@ void PlatformKWinWayland::callDBus(const QString &theGrabMethod, ArgType theArgu
}); });
} }
template <typename ArgType> template <typename ... ArgType>
void PlatformKWinWayland::doGrabHelper(const QString &theGrabMethod, ArgType theArgument) void PlatformKWinWayland::doGrabHelper(const QString &theGrabMethod, ArgType ... arguments)
{ {
int lPipeFds[2]; int lPipeFds[2];
if (pipe2(lPipeFds, O_CLOEXEC|O_NONBLOCK) != 0) { if (pipe2(lPipeFds, O_CLOEXEC|O_NONBLOCK) != 0) {
...@@ -218,8 +315,23 @@ void PlatformKWinWayland::doGrabHelper(const QString &theGrabMethod, ArgType the ...@@ -218,8 +315,23 @@ void PlatformKWinWayland::doGrabHelper(const QString &theGrabMethod, ArgType the
return; return;
} }
callDBus(theGrabMethod, theArgument, lPipeFds[1]); callDBus(theGrabMethod, lPipeFds[1], arguments...);
startReadImage(lPipeFds[0]); startReadImage(lPipeFds[0]);
close(lPipeFds[1]); close(lPipeFds[1]);
} }
template <typename ... ArgType>
void PlatformKWinWayland::doGrabImagesHelper(const QString &theGrabMethod, ArgType ... arguments)
{
int lPipeFds[2];
if (pipe2(lPipeFds, O_CLOEXEC|O_NONBLOCK) != 0) {
emit newScreenshotFailed();
return;
}
callDBus(theGrabMethod, lPipeFds[1], arguments...);
startReadImages(lPipeFds[0]);
close(lPipeFds[1]);
}
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#include "Platform.h" #include "Platform.h"
class QDBusPendingCall;
class PlatformKWinWayland final: public Platform class PlatformKWinWayland final: public Platform
{ {
Q_OBJECT Q_OBJECT
...@@ -43,6 +45,13 @@ class PlatformKWinWayland final: public Platform ...@@ -43,6 +45,13 @@ class PlatformKWinWayland final: public Platform
private: private:
void startReadImage(int theReadPipe); void startReadImage(int theReadPipe);
template <typename ArgType> void doGrabHelper(const QString &theGrabMethod, ArgType theArgument); void startReadImages(int theReadPipe);
template <typename ArgType> void callDBus(const QString &theGrabMethod, ArgType theArgument, int theWriteFile); void checkDbusPendingCall(QDBusPendingCall pcall);
bool screenshotScreensAvailable() const;
template <typename ... ArgType> void callDBus(const QString &theGrabMethod, int theWriteFile, ArgType ... arguments);
template <typename ... ArgType> void doGrabHelper(const QString &theGrabMethod, ArgType ... arguments);
template <typename ... ArgType> void doGrabImagesHelper(const QString &theGrabMethod, ArgType ... arguments);
}; };
...@@ -36,7 +36,7 @@ QString PlatformNull::platformName() const ...@@ -36,7 +36,7 @@ QString PlatformNull::platformName() const
Platform::GrabModes PlatformNull::supportedGrabModes() const Platform::GrabModes PlatformNull::supportedGrabModes() const
{ {
return { GrabMode::AllScreens | GrabMode::CurrentScreen | GrabMode::ActiveWindow | GrabMode::WindowUnderCursor | GrabMode::TransientWithParent }; return { GrabMode::AllScreens | GrabMode::CurrentScreen | GrabMode::ActiveWindow | GrabMode::WindowUnderCursor | GrabMode::TransientWithParent | GrabMode::AllScreensScaled };
} }
Platform::ShutterModes PlatformNull::supportedShutterModes() const Platform::ShutterModes PlatformNull::supportedShutterModes() const
......
...@@ -151,7 +151,7 @@ QString PlatformXcb::platformName() const ...@@ -151,7 +151,7 @@ QString PlatformXcb::platformName() const
Platform::GrabModes PlatformXcb::supportedGrabModes() const Platform::GrabModes PlatformXcb::supportedGrabModes() const
{ {
Platform::GrabModes lSupportedModes({ GrabMode::AllScreens, GrabMode::ActiveWindow, GrabMode::WindowUnderCursor, GrabMode::TransientWithParent }); Platform::GrabModes lSupportedModes({ GrabMode::AllScreens, GrabMode::ActiveWindow, GrabMode::WindowUnderCursor, GrabMode::TransientWithParent, GrabMode::PerScreenImageNative });
if (QApplication::screens().count() > 1) { if (QApplication::screens().count() > 1) {
lSupportedModes |= Platform::GrabMode::CurrentScreen; lSupportedModes |= Platform::GrabMode::CurrentScreen;
} }
...@@ -689,8 +689,22 @@ void PlatformXcb::doGrabNow(GrabMode theGrabMode, bool theIncludePointer, bool t ...@@ -689,8 +689,22 @@ void PlatformXcb::doGrabNow(GrabMode theGrabMode, bool theIncludePointer, bool t
{ {
switch(theGrabMode) { switch(theGrabMode) {
case GrabMode::AllScreens: case GrabMode::AllScreens:
case GrabMode::AllScreensScaled:
grabAllScreens(theIncludePointer); grabAllScreens(theIncludePointer);
break; break;
case GrabMode::PerScreenImageNative:{
auto lPixmap = getToplevelPixmap(QRect(), theIncludePointer);
// break thePixmap into list of images
const auto screens = QGuiApplication::screens();
QVector<QImage> images;
for (const auto screen: screens) {
QRect geom = screen->geometry();
geom.setSize(screen->size() * screen->devicePixelRatio());
images << lPixmap.copy(geom).toImage();
}
emit newScreensScreenshotTaken(images);
break;
}
case GrabMode::CurrentScreen: case GrabMode::CurrentScreen:
grabCurrentScreen(theIncludePointer); grabCurrentScreen(theIncludePointer);
break; break;
......
/*
* Copyright (C) 2020 Méven Car <meven.car@enioka.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <QPoint>
#ifndef COMPARABLEQPOINT_H
#define COMPARABLEQPOINT_H
class ComparableQPoint : public QPoint
{
public:
ComparableQPoint(const QPoint &point): QPoint(point.x(), point.y())
{}
ComparableQPoint(): QPoint()
{}
// utility class that allows using QMap to sort its keys when they are QPoint
bool operator<(const ComparableQPoint &other) const {
return x() < other.x() || y() < other.y();
}
};
#endif // COMPARABLEQPOINT_H
This diff is collapsed.
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "ComparableQPoint.h"
class QMouseEvent; class QMouseEvent;
namespace KWayland { namespace KWayland {
...@@ -41,7 +43,7 @@ class QuickEditor: public QWidget ...@@ -41,7 +43,7 @@ class QuickEditor: public QWidget
public: public:
explicit QuickEditor(const QPixmap &thePixmap, KWayland::Client::PlasmaShell *plasmashell, QWidget *parent = nullptr); explicit QuickEditor(const QMap<ComparableQPoint, QImage> &images, KWayland::Client::PlasmaShell *plasmashell, QWidget *parent = nullptr);
virtual ~QuickEditor() = default; virtual ~QuickEditor() = default;
private: private:
...@@ -117,7 +119,7 @@ class QuickEditor: public QWidget ...@@ -117,7 +119,7 @@ class QuickEditor: public QWidget
QColor mCrossColor; QColor mCrossColor;
QColor mLabelBackgroundColor; QColor mLabelBackgroundColor;
QColor mLabelForegroundColor; QColor mLabelForegroundColor;
QRectF mSelection; QRect mSelection;
QPointF mStartPos; QPointF mStartPos;
QPointF mInitialTopLeft; QPointF mInitialTopLeft;
QString mMidHelpText; QString mMidHelpText;
...@@ -128,8 +130,11 @@ class QuickEditor: public QWidget ...@@ -128,8 +130,11 @@ class QuickEditor: public QWidget
QPoint mBottomHelpContentPos; QPoint mBottomHelpContentPos;
int mBottomHelpGridLeftWidth; int mBottomHelpGridLeftWidth;
MouseState mMouseDragState; MouseState mMouseDragState;
QMap<ComparableQPoint, QImage> mImages;
QVector<QPair<QRect, qreal>> mRectToDpr;
QPixmap mPixmap; QPixmap mPixmap;
qreal dprI; qreal devicePixelRatio;
qreal devicePixelRatioI;
QPointF mMousePos; QPointF mMousePos;
bool mMagnifierAllowed; bool mMagnifierAllowed;
bool mShowMagnifier; bool mShowMagnifier;
...@@ -139,6 +144,7 @@ class QuickEditor: public QWidget ...@@ -139,6 +144,7 @@ class QuickEditor: public QWidget
bool mDisableArrowKeys; bool mDisableArrowKeys;
QRect mPrimaryScreenGeo; QRect mPrimaryScreenGeo;
int mbottomHelpLength; int mbottomHelpLength;
QRegion mScreenRegion;
// Midpoints of handles // Midpoints of handles
QVector<QPointF> mHandlePositions = QVector<QPointF> {8}; QVector<QPointF> mHandlePositions = QVector<QPointF> {8};
...@@ -149,6 +155,12 @@ Q_SIGNALS: ...@@ -149,6 +155,12 @@ Q_SIGNALS:
void grabDone(const QPixmap &thePixmap); void grabDone(const QPixmap &thePixmap);
void grabCancelled(); void grabCancelled();
private:
QMap<ComparableQPoint, ComparableQPoint> computeCoordinatesAfterScaling(QMap<ComparableQPoint, QPair<qreal, QSize>> outputsRect);
void preparePaint();