From 27bb2c156f73a7d344beb2f3ecbeb8a0041e4fe3 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Sun, 27 Jan 2019 09:45:19 +1000 Subject: [PATCH] Fix undersized layertree icons on hidpi displays --- .../layertree/qgslayertreemodel.sip.in | 11 +++++++++++ src/core/layertree/qgslayertreemodel.cpp | 12 ++++++++++-- src/core/layertree/qgslayertreemodel.h | 11 +++++++++++ .../layertree/qgslayertreemodellegendnode.cpp | 17 ++++++++++------- 4 files changed, 42 insertions(+), 9 deletions(-) diff --git a/python/core/auto_generated/layertree/qgslayertreemodel.sip.in b/python/core/auto_generated/layertree/qgslayertreemodel.sip.in index 00a74025ebe..f1a9aac3f7f 100644 --- a/python/core/auto_generated/layertree/qgslayertreemodel.sip.in +++ b/python/core/auto_generated/layertree/qgslayertreemodel.sip.in @@ -307,6 +307,17 @@ Gets map of map layer style overrides (key: layer ID, value: style name) where a Sets map of map layer style overrides (key: layer ID, value: style name) where a different style should be used instead of the current one .. versionadded:: 2.10 +%End + + static int scaleIconSize( int standardSize ); +%Docstring +Scales an layer tree model icon size to compensate for display pixel density, making the icon +size hi-dpi friendly, whilst still resulting in pixel-perfect sizes for low-dpi +displays. + +``standardSize`` should be set to a standard icon size, e.g. 16, 24, 48, etc. + +.. versionadded:: 3.6 %End protected slots: diff --git a/src/core/layertree/qgslayertreemodel.cpp b/src/core/layertree/qgslayertreemodel.cpp index 6a42f61339f..5545e5a4d2c 100644 --- a/src/core/layertree/qgslayertreemodel.cpp +++ b/src/core/layertree/qgslayertreemodel.cpp @@ -224,10 +224,11 @@ QVariant QgsLayerTreeModel::data( const QModelIndex &index, int role ) const if ( vlayer && vlayer->isEditable() ) { - QPixmap pixmap( icon.pixmap( 16, 16 ) ); + const int iconSize = scaleIconSize( 16 ); + QPixmap pixmap( icon.pixmap( iconSize, iconSize ) ); QPainter painter( &pixmap ); - painter.drawPixmap( 0, 0, 16, 16, QgsApplication::getThemePixmap( vlayer->isModified() ? "/mIconEditableEdits.svg" : "/mActionToggleEditing.svg" ) ); + painter.drawPixmap( 0, 0, iconSize, iconSize, QgsApplication::getThemePixmap( vlayer->isModified() ? QStringLiteral( "/mIconEditableEdits.svg" ) : QStringLiteral( "/mActionToggleEditing.svg" ) ) ); painter.end(); icon = QIcon( pixmap ); @@ -690,6 +691,13 @@ void QgsLayerTreeModel::setLayerStyleOverrides( const QMap &ov mLayerStyleOverrides = overrides; } +int QgsLayerTreeModel::scaleIconSize( int standardSize ) +{ + QFontMetrics fm( ( QFont() ) ); + const double scale = 1.1 * standardSize / 24; + return static_cast< int >( std::floor( std::max( Qgis::UI_SCALE_FACTOR * fm.height() * scale, static_cast< double >( standardSize ) ) ) ); +} + void QgsLayerTreeModel::nodeWillAddChildren( QgsLayerTreeNode *node, int indexFrom, int indexTo ) { Q_ASSERT( node ); diff --git a/src/core/layertree/qgslayertreemodel.h b/src/core/layertree/qgslayertreemodel.h index aac21d7b937..a266193fc3e 100644 --- a/src/core/layertree/qgslayertreemodel.h +++ b/src/core/layertree/qgslayertreemodel.h @@ -274,6 +274,17 @@ class CORE_EXPORT QgsLayerTreeModel : public QAbstractItemModel */ void setLayerStyleOverrides( const QMap &overrides ); + /** + * Scales an layer tree model icon size to compensate for display pixel density, making the icon + * size hi-dpi friendly, whilst still resulting in pixel-perfect sizes for low-dpi + * displays. + * + * \a standardSize should be set to a standard icon size, e.g. 16, 24, 48, etc. + * + * \since QGIS 3.6 + */ + static int scaleIconSize( int standardSize ); + protected slots: void nodeWillAddChildren( QgsLayerTreeNode *node, int indexFrom, int indexTo ); void nodeAddedChildren( QgsLayerTreeNode *node, int indexFrom, int indexTo ); diff --git a/src/core/layertree/qgslayertreemodellegendnode.cpp b/src/core/layertree/qgslayertreemodellegendnode.cpp index 863550e8d76..647f270ed25 100644 --- a/src/core/layertree/qgslayertreemodellegendnode.cpp +++ b/src/core/layertree/qgslayertreemodellegendnode.cpp @@ -130,13 +130,14 @@ QSizeF QgsLayerTreeModelLegendNode::drawSymbolText( const QgsLegendSettings &set // ------------------------------------------------------------------------- - QgsSymbolLegendNode::QgsSymbolLegendNode( QgsLayerTreeLayer *nodeLayer, const QgsLegendSymbolItem &item, QObject *parent ) : QgsLayerTreeModelLegendNode( nodeLayer, parent ) , mItem( item ) , mSymbolUsesMapUnits( false ) - , mIconSize( 16, 16 ) { + const int iconSize = QgsLayerTreeModel::scaleIconSize( 16 ); + mIconSize = QSize( iconSize, iconSize ); + updateLabel(); connect( qobject_cast( nodeLayer->layer() ), &QgsVectorLayer::symbolFeatureCountMapChanged, this, &QgsSymbolLegendNode::updateLabel ); connect( nodeLayer, &QObject::destroyed, this, [ = ]() { mLayerNode = nullptr; } ); @@ -162,11 +163,13 @@ QSize QgsSymbolLegendNode::minimumIconSize() const QSize QgsSymbolLegendNode::minimumIconSize( QgsRenderContext *context ) const { - QSize minSz( 16, 16 ); + const int iconSize = QgsLayerTreeModel::scaleIconSize( 16 ); + const int largeIconSize = QgsLayerTreeModel::scaleIconSize( 512 ); + QSize minSz( iconSize, iconSize ); if ( mItem.symbol() && mItem.symbol()->type() == QgsSymbol::Marker ) { minSz = QgsImageOperation::nonTransparentImageRect( - QgsSymbolLayerUtils::symbolPreviewPixmap( mItem.symbol(), QSize( 512, 512 ), 0, + QgsSymbolLayerUtils::symbolPreviewPixmap( mItem.symbol(), QSize( largeIconSize, largeIconSize ), 0, context ).toImage(), minSz, true ).size(); @@ -174,7 +177,7 @@ QSize QgsSymbolLegendNode::minimumIconSize( QgsRenderContext *context ) const else if ( mItem.symbol() && mItem.symbol()->type() == QgsSymbol::Line ) { minSz = QgsImageOperation::nonTransparentImageRect( - QgsSymbolLayerUtils::symbolPreviewPixmap( mItem.symbol(), QSize( minSz.width(), 512 ), 0, + QgsSymbolLayerUtils::symbolPreviewPixmap( mItem.symbol(), QSize( minSz.width(), largeIconSize ), 0, context ).toImage(), minSz, true ).size(); @@ -607,8 +610,8 @@ QVariant QgsRasterSymbolLegendNode::data( int role ) const { if ( role == Qt::DecorationRole ) { - QSize iconSize( 16, 16 ); // TODO: configurable? - QPixmap pix( iconSize ); + const int iconSize = QgsLayerTreeModel::scaleIconSize( 16 ); // TODO: configurable? + QPixmap pix( iconSize, iconSize ); pix.fill( mColor ); return QIcon( pix ); }