From 8776449a148e8b5422a73de45e5a364d1a7e5d5d Mon Sep 17 00:00:00 2001 From: vmora Date: Wed, 12 Aug 2015 15:22:18 +0200 Subject: [PATCH] Fix legend symbol size when using map units fix #13078 The computation of icon sizes for legend symbols has been moved to QgsLayerTreeModel::legendInvalidateMapBasedData() susch that icon size is recomputed when zooming. --- src/core/layertree/qgslayertreemodel.cpp | 35 +++++++++++++++++++ .../layertree/qgslayertreemodellegendnode.cpp | 15 ++++---- src/core/qgsmaplayerlegend.cpp | 23 ------------ 3 files changed, 41 insertions(+), 32 deletions(-) diff --git a/src/core/layertree/qgslayertreemodel.cpp b/src/core/layertree/qgslayertreemodel.cpp index e5cbb8c5f0c..0b940ee4b0f 100644 --- a/src/core/layertree/qgslayertreemodel.cpp +++ b/src/core/layertree/qgslayertreemodel.cpp @@ -1118,6 +1118,10 @@ void QgsLayerTreeModel::addLegendToLayer( QgsLayerTreeLayer* nodeL ) if ( hasStyleOverride ) ml->styleManager()->restoreOverrideStyle(); + + // invalidate map based data even if the data is not map-based to make sure + // the symbol sizes are computed at least once + legendInvalidateMapBasedData(); } @@ -1299,10 +1303,41 @@ QList QgsLayerTreeModel::layerLegendNodes( QgsLaye void QgsLayerTreeModel::legendInvalidateMapBasedData() { + // we have varying icon sizes, and we want icon to be centered and + // text to be left aligned, so we have to compute the max width of icons + // + // we do that for nodes who share a common parent + // + // we do that here because for symbols with size defined in map units + // the symbol sizes changes depends on the zoom level + + QList symbolNodes; + QMap widthMax; foreach ( const LayerLegendData& data, mLegend ) { foreach ( QgsLayerTreeModelLegendNode* legendNode, data.originalNodes ) + { legendNode->invalidateMapBasedData(); + QgsSymbolV2LegendNode* n = dynamic_cast( legendNode ); + if ( n ) + { + n->setParent( this ); // map scale are in the model, so the parent needs to be set + const QSize sz( n->minimumIconSize() ); + const QString parentKey( n->data( QgsLayerTreeModelLegendNode::ParentRuleKeyRole ).toString() ); + widthMax[parentKey] = qMax( sz.width(), widthMax.contains( parentKey ) ? widthMax[parentKey] : 0 ); + n->setIconSize( sz ); + symbolNodes.append( n ); + } + } + } + + foreach ( QgsSymbolV2LegendNode* n, symbolNodes ) + { + const QString parentKey( n->data( QgsLayerTreeModelLegendNode::ParentRuleKeyRole ).toString() ); + Q_ASSERT( widthMax[parentKey] > 0 ); + const int twiceMarginWidth = 2; // a one pixel margin avoids hugly rendering of icon + n->setIconSize( QSize( widthMax[parentKey] + twiceMarginWidth, n->iconSize().rheight() + twiceMarginWidth ) ); + n->invalidateMapBasedData(); } } diff --git a/src/core/layertree/qgslayertreemodellegendnode.cpp b/src/core/layertree/qgslayertreemodellegendnode.cpp index b5e3db21366..495d6ae13f1 100644 --- a/src/core/layertree/qgslayertreemodellegendnode.cpp +++ b/src/core/layertree/qgslayertreemodellegendnode.cpp @@ -159,13 +159,14 @@ Qt::ItemFlags QgsSymbolV2LegendNode::flags() const QSize QgsSymbolV2LegendNode::minimumIconSize() const { - QSize minSz; + QSize minSz( 16, 16 ); if ( mItem.symbol() && mItem.symbol()->type() == QgsSymbolV2::Marker ) { QScopedPointer context( createTemporaryRenderContext() ); minSz = QgsImageOperation::nonTransparentImageRect( - QgsSymbolLayerV2Utils::symbolPreviewPixmap( mItem.symbol(), QSize( 512, 512 ), context.data() ).toImage(), - mIconSize, + QgsSymbolLayerV2Utils::symbolPreviewPixmap( mItem.symbol(), QSize( 512, 512 ), + context.data() ).toImage(), + minSz, true ).size(); } else if ( mItem.symbol() && mItem.symbol()->type() == QgsSymbolV2::Line ) @@ -174,16 +175,12 @@ QSize QgsSymbolV2LegendNode::minimumIconSize() const minSz = QgsImageOperation::nonTransparentImageRect( QgsSymbolLayerV2Utils::symbolPreviewPixmap( mItem.symbol(), QSize( mIconSize.width(), 512 ), context.data() ).toImage(), - mIconSize, + minSz, true ).size(); } - else - { - minSz = mIconSize; - } if ( mItem.level() != 0 && !( model() && model()->testFlag( QgsLayerTreeModel::ShowLegendAsTree ) ) ) - minSz.setWidth( indentSize + minSz.width() ); + minSz.setWidth( mItem.level() * indentSize + minSz.width() ); return minSz; } diff --git a/src/core/qgsmaplayerlegend.cpp b/src/core/qgsmaplayerlegend.cpp index dd7c5f788b1..0f53e323abc 100644 --- a/src/core/qgsmaplayerlegend.cpp +++ b/src/core/qgsmaplayerlegend.cpp @@ -199,33 +199,10 @@ QList QgsDefaultVectorLayerLegend::createLayerTree nodes.append( new QgsSimpleLegendNode( nodeLayer, r->legendClassificationAttribute() ) ); } - // we have varying icon sizes, and we want icon to be centered and - // text to be left aligned, so we have to compute the max width of icons - // - // we do that for nodes who share a common parent - - QList symbolNodes; - QMap widthMax; foreach ( const QgsLegendSymbolItemV2& i, r->legendSymbolItemsV2() ) { QgsSymbolV2LegendNode * n = new QgsSymbolV2LegendNode( nodeLayer, i ); nodes.append( n ); - if ( i.symbol() ) - { - const QSize sz( n->minimumIconSize() ); - const QString parentKey( n->data( QgsLayerTreeModelLegendNode::ParentRuleKeyRole ).toString() ); - widthMax[parentKey] = qMax( sz.width(), widthMax.contains( parentKey ) ? widthMax[parentKey] : 0 ); - n->setIconSize( sz ); - symbolNodes.append( n ); - } - } - - foreach ( QgsSymbolV2LegendNode* n, symbolNodes ) - { - const QString parentKey( n->data( QgsLayerTreeModelLegendNode::ParentRuleKeyRole ).toString() ); - Q_ASSERT( widthMax[parentKey] > 0 ); - const int twiceMarginWidth = 2; // a one pixel margin avoids hugly rendering of icon - n->setIconSize( QSize( widthMax[parentKey] + twiceMarginWidth, n->iconSize().rheight() + twiceMarginWidth ) ); } if ( nodes.count() == 1 && nodes[0]->data( Qt::EditRole ).toString().isEmpty() )