diff --git a/CMakeLists.txt b/CMakeLists.txt index 2421979..691d816 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ if (OVERRIDE_QT_VERSION) set(MIN_QT_VERSION 5.4.0) endif() -set(MIN_FRAMEWORKS_VERSION 5.22.0) +set(MIN_FRAMEWORKS_VERSION 5.16.0) if (POLICY CMP0002) cmake_policy(SET CMP0002 OLD) diff --git a/libs/ui/KisView.cpp b/libs/ui/KisView.cpp index 971f6cc..a065d2a 100644 --- a/libs/ui/KisView.cpp +++ b/libs/ui/KisView.cpp @@ -55,6 +55,7 @@ #include #include #include +#include #include #include @@ -91,6 +92,8 @@ #include "krita_utils.h" #include "input/kis_input_manager.h" #include "KisRemoteFileFetcher.h" +#include "KisMainWindow.h" +#include //static QString KisView::newObjectName() @@ -151,6 +154,9 @@ public: bool softProofing = false; bool gamutCheck = false; + QScreen *currentScreen = 0; + KisSignalAutoConnectionsStore screenConnectionsStore; + // Hmm sorry for polluting the private class with such a big inner class. // At the beginning it was a little struct :) class StatusBarItem @@ -358,6 +364,8 @@ void KisView::setViewManager(KisViewManager *view) SLOT(slotContinueRemoveNode(KisNodeSP)), Qt::AutoConnection); + slotScreenChanged(d->viewManager->mainWindow()->windowHandle()->screen()); + d->viewManager->updateGUI(); KoToolManager::instance()->switchToolRequested("KritaShape/KisToolBrush"); @@ -403,6 +411,33 @@ void KisView::slotContinueRemoveNode(KisNodeSP newActiveNode) } } +void KisView::slotScreenChanged(QScreen *screen) +{ + // TODO: rerender canvas display if the zoom actually changed + + ENTER_FUNCTION() << ppVar(screen); + + d->screenConnectionsStore.clear(); + d->currentScreen = screen; + + if (screen) { + d->screenConnectionsStore.addConnection( + screen, SIGNAL(physicalDotsPerInchChanged(qreal)), + this, SLOT(slotUpdateDevicePixelRatio())); + } + slotUpdateDevicePixelRatio(); +} + +void KisView::slotUpdateDevicePixelRatio() +{ + ENTER_FUNCTION(); + + const qreal ratio = + d->currentScreen ? d->currentScreen->devicePixelRatio() : 1.0; + + d->viewConverter.setDevicePixelRatio(ratio); +} + KoZoomController *KisView::zoomController() const { return d->zoomManager.zoomController(); diff --git a/libs/ui/KisView.h b/libs/ui/KisView.h index 2b76495..46bcdc5 100644 --- a/libs/ui/KisView.h +++ b/libs/ui/KisView.h @@ -253,6 +253,9 @@ private Q_SLOTS: void slotImageNodeRemoved(KisNodeSP node); void slotContinueRemoveNode(KisNodeSP newActiveNode); + void slotScreenChanged(QScreen *screen); + void slotUpdateDevicePixelRatio(); + Q_SIGNALS: // From KisImage void sigSizeChanged(const QPointF &oldStillPoint, const QPointF &newStillPoint); diff --git a/libs/ui/canvas/kis_coordinates_converter.cpp b/libs/ui/canvas/kis_coordinates_converter.cpp index 36f6aa4..f5df3b5 100644 --- a/libs/ui/canvas/kis_coordinates_converter.cpp +++ b/libs/ui/canvas/kis_coordinates_converter.cpp @@ -44,6 +44,8 @@ struct KisCoordinatesConverter::Private { QTransform imageToDocument; QTransform documentToFlake; QTransform widgetToViewport; + + qreal devicePixelRatio = 1.0; }; /** @@ -129,6 +131,7 @@ void KisCoordinatesConverter::recalculateTransformations() QRectF rrect = irect & wrect; QTransform reversedTransform = flakeToWidgetTransform().inverted(); + reversedTransform *= QTransform::fromScale(m_d->devicePixelRatio, m_d->devicePixelRatio); QRectF canvasBounds = reversedTransform.mapRect(rrect); QPointF offset = canvasBounds.topLeft(); @@ -194,6 +197,11 @@ qreal KisCoordinatesConverter::effectiveZoom() const return 0.5 * (scaleX + scaleY); } +qreal KisCoordinatesConverter::effectiveDeviceZoom() const +{ + return effectiveZoom() * m_d->devicePixelRatio; +} + QPoint KisCoordinatesConverter::rotate(QPointF center, qreal angle) { QTransform rot; @@ -277,6 +285,19 @@ QPoint KisCoordinatesConverter::resetRotation(QPointF center) return m_d->documentOffset.toPoint(); } +void KisCoordinatesConverter::setDevicePixelRatio(qreal value) +{ + ENTER_FUNCTION() << ppVar(value); + + m_d->devicePixelRatio = value; + recalculateTransformations(); +} + +qreal KisCoordinatesConverter::devicePixelRatio() const +{ + return m_d->devicePixelRatio; +} + QTransform KisCoordinatesConverter::imageToWidgetTransform() const{ return m_d->imageToDocument * m_d->documentToFlake * m_d->flakeToWidget; } @@ -298,6 +319,18 @@ QTransform KisCoordinatesConverter::documentToWidgetTransform() const return m_d->documentToFlake * m_d->flakeToWidget; } +QTransform KisCoordinatesConverter::widgetToDisplayDeviceTransform() const +{ + return QTransform::fromScale(m_d->devicePixelRatio, m_d->devicePixelRatio); +} + +QTransform KisCoordinatesConverter::imageToDisplayDeviceTransform() const +{ + //return m_d->imageToDocument * m_d->documentToFlake * QTransform::fromScale(m_d->devicePixelRatio, m_d->devicePixelRatio) * m_d->flakeToWidget; + return imageToWidgetTransform() * widgetToDisplayDeviceTransform(); + +} + QTransform KisCoordinatesConverter::viewportToWidgetTransform() const { return m_d->widgetToViewport.inverted(); } @@ -347,11 +380,11 @@ void KisCoordinatesConverter::getOpenGLCheckersInfo(const QRectF &viewportRect, *textureRect = QRectF(0, 0, viewportRect.width(),viewportRect.height()); } else { - *textureTransform = viewportToWidgetTransform(); + *textureTransform = viewportToWidgetTransform() * widgetToDisplayDeviceTransform(); *textureRect = viewportRect; } - *modelTransform = viewportToWidgetTransform(); + *modelTransform = viewportToWidgetTransform() * widgetToDisplayDeviceTransform(); *modelRect = viewportRect; } diff --git a/libs/ui/canvas/kis_coordinates_converter.h b/libs/ui/canvas/kis_coordinates_converter.h index e7ce76b..c8927a2 100644 --- a/libs/ui/canvas/kis_coordinates_converter.h +++ b/libs/ui/canvas/kis_coordinates_converter.h @@ -72,6 +72,9 @@ public: bool yAxisMirrored() const; QPoint resetRotation(QPointF center); + void setDevicePixelRatio(qreal value); + qreal devicePixelRatio() const; + void setZoom(qreal zoom) override; /** @@ -79,6 +82,12 @@ public: */ qreal effectiveZoom() const; + /** + * A composition of effectiveZoom() and device pixel ratio used for + * scaling in HiDPI mode + */ + qreal effectiveDeviceZoom() const; + template typename _Private::Traits::Result imageToViewport(const T& obj) const { return _Private::Traits::map(imageToViewportTransform(), obj); } template typename _Private::Traits::Result @@ -122,6 +131,9 @@ public: QTransform flakeToWidgetTransform() const; QTransform documentToWidgetTransform() const; + QTransform widgetToDisplayDeviceTransform() const; + QTransform imageToDisplayDeviceTransform() const; + void getQPainterCheckersInfo(QTransform *transform, QPointF *brushOrigin, QPolygonF *poligon, diff --git a/libs/ui/opengl/kis_opengl_canvas2.cpp b/libs/ui/opengl/kis_opengl_canvas2.cpp index 0de410b..f284a4a 100644 --- a/libs/ui/opengl/kis_opengl_canvas2.cpp +++ b/libs/ui/opengl/kis_opengl_canvas2.cpp @@ -228,6 +228,9 @@ inline void rectToTexCoords(QVector2D* texCoords, const QRectF &rc) texCoords[5] = QVector2D(rc.right(), rc.bottom()); } +#include +#include + void KisOpenGLCanvas2::initializeGL() { KisOpenGL::initializeContext(context()); @@ -289,6 +292,13 @@ void KisOpenGLCanvas2::initializeGL() Sync::init(context()); d->canvasInitialized = true; + + ENTER_FUNCTION() << ppVar(devicePixelRatioF()); + ENTER_FUNCTION() << ppVar(window()->windowHandle()); + + if (window()->windowHandle()) { + ENTER_FUNCTION() << ppVar(window()->windowHandle()->screen()); + } } /** @@ -626,7 +636,7 @@ void KisOpenGLCanvas2::drawImage() projectionMatrix.ortho(0, width(), height(), 0, NEAR_VAL, FAR_VAL); // Set view/projection matrices - QMatrix4x4 modelMatrix(converter->imageToWidgetTransform()); + QMatrix4x4 modelMatrix(converter->imageToDisplayDeviceTransform()); modelMatrix.optimize(); modelMatrix = projectionMatrix * modelMatrix; d->displayShader->setUniformValue(d->displayShader->location(Uniform::ModelViewProjection), modelMatrix); @@ -638,9 +648,9 @@ void KisOpenGLCanvas2::drawImage() QRectF widgetRect(0,0, width(), height()); QRectF widgetRectInImagePixels = converter->documentToImage(converter->widgetToDocument(widgetRect)); - qreal scaleX, scaleY; - converter->imageScale(&scaleX, &scaleY); - d->displayShader->setUniformValue(d->displayShader->location(Uniform::ViewportScale), (GLfloat) scaleX); + const qreal effectiveDeviceScale = converter->effectiveDeviceZoom(); + + d->displayShader->setUniformValue(d->displayShader->location(Uniform::ViewportScale), (GLfloat) effectiveDeviceScale); d->displayShader->setUniformValue(d->displayShader->location(Uniform::TexelSize), (GLfloat) d->openGLImageTextures->texelSize()); QRect ir = d->openGLImageTextures->storedImageBounds(); @@ -739,7 +749,7 @@ void KisOpenGLCanvas2::drawImage() if (currentLodPlane > 0) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); - } else if (SCALE_MORE_OR_EQUAL_TO(scaleX, scaleY, 2.0)) { + } else if (effectiveDeviceScale >= 2.0) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } else { @@ -757,7 +767,7 @@ void KisOpenGLCanvas2::drawImage() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); break; case KisOpenGL::HighQualityFiltering: - if (SCALE_LESS_THAN(scaleX, scaleY, 0.5)) { + if (effectiveDeviceScale < 0.5) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);