From 730081dceb38f59b0a4cef507ca82c7b679e5ade Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Tue, 20 Jun 2023 13:52:00 +1000 Subject: [PATCH] Handle view device pixel ratio when generating preview icons for text format and label settings --- .../labeling/qgspallabeling.sip.in | 3 ++- .../textrenderer/qgstextformat.sip.in | 3 ++- src/core/labeling/qgspallabeling.cpp | 13 ++++++----- src/core/labeling/qgspallabeling.h | 3 ++- src/core/symbology/qgsstylemodel.cpp | 22 ++++++++++++------- src/core/textrenderer/qgstextformat.cpp | 13 ++++++----- src/core/textrenderer/qgstextformat.h | 3 ++- 7 files changed, 38 insertions(+), 22 deletions(-) diff --git a/python/core/auto_generated/labeling/qgspallabeling.sip.in b/python/core/auto_generated/labeling/qgspallabeling.sip.in index 1dfe311bb6c..00a82f357b5 100644 --- a/python/core/auto_generated/labeling/qgspallabeling.sip.in +++ b/python/core/auto_generated/labeling/qgspallabeling.sip.in @@ -636,7 +636,7 @@ Sets the label placement ``settings``. .. versionadded:: 3.26 %End - static QPixmap labelSettingsPreviewPixmap( const QgsPalLayerSettings &settings, QSize size, const QString &previewText = QString(), int padding = 0 ); + static QPixmap labelSettingsPreviewPixmap( const QgsPalLayerSettings &settings, QSize size, const QString &previewText = QString(), int padding = 0, double devicePixelRatio = 1 ); %Docstring Returns a pixmap preview for label ``settings``. @@ -644,6 +644,7 @@ Returns a pixmap preview for label ``settings``. :param size: target pixmap size :param previewText: text to render in preview, or empty for default text :param padding: space between icon edge and color ramp +:param devicePixelRatio: can be used to generate a pixmap using a specific device pixel ratio (since QGIS 3.32) .. versionadded:: 3.10 %End diff --git a/python/core/auto_generated/textrenderer/qgstextformat.sip.in b/python/core/auto_generated/textrenderer/qgstextformat.sip.in index 58f5e77489b..4f0ee9e176e 100644 --- a/python/core/auto_generated/textrenderer/qgstextformat.sip.in +++ b/python/core/auto_generated/textrenderer/qgstextformat.sip.in @@ -708,7 +708,7 @@ Updates the format by evaluating current values of data defined properties. .. versionadded:: 3.10 %End - static QPixmap textFormatPreviewPixmap( const QgsTextFormat &format, QSize size, const QString &previewText = QString(), int padding = 0 ); + static QPixmap textFormatPreviewPixmap( const QgsTextFormat &format, QSize size, const QString &previewText = QString(), int padding = 0, double devicePixelRatio = 1 ); %Docstring Returns a pixmap preview for a text ``format``. @@ -716,6 +716,7 @@ Returns a pixmap preview for a text ``format``. :param size: target pixmap size :param previewText: text to render in preview, or empty for default text :param padding: space between icon edge and color ramp +:param devicePixelRatio: can be used to generate a pixmap using a specific device pixel ratio (since QGIS 3.32) .. versionadded:: 3.10 %End diff --git a/src/core/labeling/qgspallabeling.cpp b/src/core/labeling/qgspallabeling.cpp index 2a6c245bf5a..ebc02dd7ac9 100644 --- a/src/core/labeling/qgspallabeling.cpp +++ b/src/core/labeling/qgspallabeling.cpp @@ -1357,18 +1357,19 @@ void QgsPalLayerSettings::setCallout( QgsCallout *callout ) mCallout.reset( callout ); } -QPixmap QgsPalLayerSettings::labelSettingsPreviewPixmap( const QgsPalLayerSettings &settings, QSize size, const QString &previewText, int padding ) +QPixmap QgsPalLayerSettings::labelSettingsPreviewPixmap( const QgsPalLayerSettings &settings, QSize size, const QString &previewText, int padding, double devicePixelRatio ) { // for now, just use format QgsTextFormat tempFormat = settings.format(); - QPixmap pixmap( size ); + QPixmap pixmap( size * devicePixelRatio ); pixmap.fill( Qt::transparent ); + pixmap.setDevicePixelRatio( devicePixelRatio ); QPainter painter; painter.begin( &pixmap ); painter.setRenderHint( QPainter::Antialiasing ); - QRect rect( 0, 0, size.width(), size.height() ); + const QRectF rect( 0, 0, size.width(), size.height() ); // shameless eye candy - use a subtle gradient when drawing background painter.setPen( Qt::NoPen ); @@ -1406,8 +1407,10 @@ QPixmap QgsPalLayerSettings::labelSettingsPreviewPixmap( const QgsPalLayerSettin context.setFlag( Qgis::RenderContextFlag::Antialiasing, true ); QWidget *activeWindow = QApplication::activeWindow(); - const double logicalDpiX = activeWindow && activeWindow->screen() ? activeWindow->screen()->logicalDotsPerInchX() : 96.0; - context.setScaleFactor( logicalDpiX / 25.4 ); + const double physicalDpiX = activeWindow && activeWindow->screen() ? activeWindow->screen()->physicalDotsPerInchX() : 96.0; + context.setScaleFactor( physicalDpiX / 25.4 ); + context.setDevicePixelRatio( devicePixelRatio ); + context.setUseAdvancedEffects( true ); context.setPainter( &painter ); diff --git a/src/core/labeling/qgspallabeling.h b/src/core/labeling/qgspallabeling.h index 7103b2db62d..5c9e6662c68 100644 --- a/src/core/labeling/qgspallabeling.h +++ b/src/core/labeling/qgspallabeling.h @@ -968,9 +968,10 @@ class CORE_EXPORT QgsPalLayerSettings * \param size target pixmap size * \param previewText text to render in preview, or empty for default text * \param padding space between icon edge and color ramp + * \param devicePixelRatio can be used to generate a pixmap using a specific device pixel ratio (since QGIS 3.32) * \since QGIS 3.10 */ - static QPixmap labelSettingsPreviewPixmap( const QgsPalLayerSettings &settings, QSize size, const QString &previewText = QString(), int padding = 0 ); + static QPixmap labelSettingsPreviewPixmap( const QgsPalLayerSettings &settings, QSize size, const QString &previewText = QString(), int padding = 0, double devicePixelRatio = 1 ); /** * Returns the layer's unplaced label visibility. diff --git a/src/core/symbology/qgsstylemodel.cpp b/src/core/symbology/qgsstylemodel.cpp index d9624dfa17f..76ca352563b 100644 --- a/src/core/symbology/qgsstylemodel.cpp +++ b/src/core/symbology/qgsstylemodel.cpp @@ -302,11 +302,14 @@ QVariant QgsStyleModel::data( const QModelIndex &index, int role ) const return icon; const QgsTextFormat format( mStyle->textFormat( name ) ); - if ( mAdditionalSizes.isEmpty() ) - icon.addPixmap( QgsTextFormat::textFormatPreviewPixmap( format, QSize( 24, 24 ), QString(), 1 ) ); - for ( const QSize &s : mAdditionalSizes ) + for ( const double pixelRatio : std::as_const( mDevicePixelRatios ) ) { - icon.addPixmap( QgsTextFormat::textFormatPreviewPixmap( format, s, QString(), static_cast< int >( s.width() * ICON_PADDING_FACTOR ) ) ); + if ( mAdditionalSizes.isEmpty() ) + icon.addPixmap( QgsTextFormat::textFormatPreviewPixmap( format, QSize( 24, 24 ), QString(), 1, pixelRatio ) ); + for ( const QSize &s : mAdditionalSizes ) + { + icon.addPixmap( QgsTextFormat::textFormatPreviewPixmap( format, s, QString(), static_cast< int >( s.width() * ICON_PADDING_FACTOR ), pixelRatio ) ); + } } mIconCache[ entityType ].insert( name, icon ); return icon; @@ -320,11 +323,14 @@ QVariant QgsStyleModel::data( const QModelIndex &index, int role ) const return icon; const QgsPalLayerSettings settings( mStyle->labelSettings( name ) ); - if ( mAdditionalSizes.isEmpty() ) - icon.addPixmap( QgsPalLayerSettings::labelSettingsPreviewPixmap( settings, QSize( 24, 24 ), QString(), 1 ) ); - for ( const QSize &s : mAdditionalSizes ) + for ( const double pixelRatio : std::as_const( mDevicePixelRatios ) ) { - icon.addPixmap( QgsPalLayerSettings::labelSettingsPreviewPixmap( settings, s, QString(), static_cast< int >( s.width() * ICON_PADDING_FACTOR ) ) ); + if ( mAdditionalSizes.isEmpty() ) + icon.addPixmap( QgsPalLayerSettings::labelSettingsPreviewPixmap( settings, QSize( 24, 24 ), QString(), 1, pixelRatio ) ); + for ( const QSize &s : mAdditionalSizes ) + { + icon.addPixmap( QgsPalLayerSettings::labelSettingsPreviewPixmap( settings, s, QString(), static_cast< int >( s.width() * ICON_PADDING_FACTOR ), pixelRatio ) ); + } } mIconCache[ entityType ].insert( name, icon ); return icon; diff --git a/src/core/textrenderer/qgstextformat.cpp b/src/core/textrenderer/qgstextformat.cpp index 3983b3cc73d..8e2b25676cd 100644 --- a/src/core/textrenderer/qgstextformat.cpp +++ b/src/core/textrenderer/qgstextformat.cpp @@ -1093,17 +1093,19 @@ void QgsTextFormat::updateDataDefinedProperties( QgsRenderContext &context ) mMaskSettings.updateDataDefinedProperties( context, d->mDataDefinedProperties ); } -QPixmap QgsTextFormat::textFormatPreviewPixmap( const QgsTextFormat &format, QSize size, const QString &previewText, int padding ) +QPixmap QgsTextFormat::textFormatPreviewPixmap( const QgsTextFormat &format, QSize size, const QString &previewText, int padding, double devicePixelRatio ) { QgsTextFormat tempFormat = format; - QPixmap pixmap( size ); + QPixmap pixmap( size * devicePixelRatio ); pixmap.fill( Qt::transparent ); + pixmap.setDevicePixelRatio( devicePixelRatio ); + QPainter painter; painter.begin( &pixmap ); painter.setRenderHint( QPainter::Antialiasing ); - QRect rect( 0, 0, size.width(), size.height() ); + const QRectF rect( 0, 0, size.width(), size.height() ); // shameless eye candy - use a subtle gradient when drawing background painter.setPen( Qt::NoPen ); @@ -1140,8 +1142,9 @@ QPixmap QgsTextFormat::textFormatPreviewPixmap( const QgsTextFormat &format, QSi context.setMapToPixel( newCoordXForm ); QWidget *activeWindow = QApplication::activeWindow(); - const double logicalDpiX = activeWindow && activeWindow->screen() ? activeWindow->screen()->logicalDotsPerInchX() : 96.0; - context.setScaleFactor( logicalDpiX / 25.4 ); + const double physicalDpiX = ( activeWindow && activeWindow->screen() ? activeWindow->screen()->physicalDotsPerInch() : 96.0 ); + context.setScaleFactor( physicalDpiX / 25.4 ); + context.setDevicePixelRatio( devicePixelRatio ); context.setUseAdvancedEffects( true ); context.setFlag( Qgis::RenderContextFlag::Antialiasing, true ); diff --git a/src/core/textrenderer/qgstextformat.h b/src/core/textrenderer/qgstextformat.h index 0fb466ec8a5..e965d2b61e2 100644 --- a/src/core/textrenderer/qgstextformat.h +++ b/src/core/textrenderer/qgstextformat.h @@ -641,9 +641,10 @@ class CORE_EXPORT QgsTextFormat * \param size target pixmap size * \param previewText text to render in preview, or empty for default text * \param padding space between icon edge and color ramp + * \param devicePixelRatio can be used to generate a pixmap using a specific device pixel ratio (since QGIS 3.32) * \since QGIS 3.10 */ - static QPixmap textFormatPreviewPixmap( const QgsTextFormat &format, QSize size, const QString &previewText = QString(), int padding = 0 ); + static QPixmap textFormatPreviewPixmap( const QgsTextFormat &format, QSize size, const QString &previewText = QString(), int padding = 0, double devicePixelRatio = 1 ); private: