Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Fix undersized layertree icons on hidpi displays
  • Loading branch information
nyalldawson committed Jan 27, 2019
1 parent fc9796f commit 27bb2c1
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 9 deletions.
11 changes: 11 additions & 0 deletions python/core/auto_generated/layertree/qgslayertreemodel.sip.in
Expand Up @@ -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:
Expand Down
12 changes: 10 additions & 2 deletions src/core/layertree/qgslayertreemodel.cpp
Expand Up @@ -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 );
Expand Down Expand Up @@ -690,6 +691,13 @@ void QgsLayerTreeModel::setLayerStyleOverrides( const QMap<QString, QString> &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 );
Expand Down
11 changes: 11 additions & 0 deletions src/core/layertree/qgslayertreemodel.h
Expand Up @@ -274,6 +274,17 @@ class CORE_EXPORT QgsLayerTreeModel : public QAbstractItemModel
*/
void setLayerStyleOverrides( const QMap<QString, QString> &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 );
Expand Down
17 changes: 10 additions & 7 deletions src/core/layertree/qgslayertreemodellegendnode.cpp
Expand Up @@ -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<QgsVectorLayer *>( nodeLayer->layer() ), &QgsVectorLayer::symbolFeatureCountMapChanged, this, &QgsSymbolLegendNode::updateLabel );
connect( nodeLayer, &QObject::destroyed, this, [ = ]() { mLayerNode = nullptr; } );
Expand All @@ -162,19 +163,21 @@ 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();
}
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();
Expand Down Expand Up @@ -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 );
}
Expand Down

0 comments on commit 27bb2c1

Please sign in to comment.