Skip to content

Commit

Permalink
[layouts] Fix legend symbol rendering doesn't respect linked map
Browse files Browse the repository at this point in the history
scale when symbol uses map unit based sizes

Fixes #38326
  • Loading branch information
nyalldawson committed Sep 21, 2020
1 parent 96753cf commit 426ee21
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 16 deletions.
19 changes: 15 additions & 4 deletions src/core/layout/qgslayoutitemlegend.cpp
Expand Up @@ -129,7 +129,9 @@ void QgsLayoutItemLegend::paint( QPainter *painter, const QStyleOptionGraphicsIt
//adjust box if width or height is too small
if ( mSizeToContents )
{
QgsRenderContext context = QgsLayoutUtils::createRenderContextForLayout( mLayout, painter );
QgsRenderContext context = mMap ? QgsLayoutUtils::createRenderContextForMap( mMap, painter )
: QgsLayoutUtils::createRenderContextForLayout( mLayout, painter );

QSizeF size = legendRenderer.minimumSize( &context );
if ( mForceResize )
{
Expand Down Expand Up @@ -175,10 +177,14 @@ void QgsLayoutItemLegend::refresh()
void QgsLayoutItemLegend::draw( QgsLayoutItemRenderContext &context )
{
QPainter *painter = context.renderContext().painter();

QgsRenderContext rc = mMap ? QgsLayoutUtils::createRenderContextForMap( mMap, painter, context.renderContext().scaleFactor() * 25.4 )
: QgsLayoutUtils::createRenderContextForLayout( mLayout, painter, context.renderContext().scaleFactor() * 25.4 );

QgsScopedQPainterState painterState( painter );

// painter is scaled to dots, so scale back to layout units
painter->scale( context.renderContext().scaleFactor(), context.renderContext().scaleFactor() );
painter->scale( rc.scaleFactor(), rc.scaleFactor() );

painter->setPen( QPen( QColor( 0, 0, 0 ) ) );

Expand All @@ -197,10 +203,13 @@ void QgsLayoutItemLegend::draw( QgsLayoutItemRenderContext &context )
Q_NOWARN_DEPRECATED_POP
}




QgsLegendRenderer legendRenderer( mLegendModel.get(), mSettings );
legendRenderer.setLegendSize( rect().size() );

legendRenderer.drawLegend( context.renderContext() );
legendRenderer.drawLegend( rc );
}

void QgsLayoutItemLegend::adjustBoxSize()
Expand All @@ -217,7 +226,9 @@ void QgsLayoutItemLegend::adjustBoxSize()
return;
}

QgsRenderContext context = QgsLayoutUtils::createRenderContextForLayout( mLayout, nullptr );
QgsRenderContext context = mMap ? QgsLayoutUtils::createRenderContextForMap( mMap, nullptr ) :
QgsLayoutUtils::createRenderContextForLayout( mLayout, nullptr );

QgsLegendRenderer legendRenderer( mLegendModel.get(), mSettings );
QSizeF size = legendRenderer.minimumSize( &context );
QgsDebugMsg( QStringLiteral( "width = %1 height = %2" ).arg( size.width() ).arg( size.height() ) );
Expand Down
83 changes: 71 additions & 12 deletions tests/src/python/test_qgslayoutlegend.py
Expand Up @@ -57,14 +57,13 @@ class TestQgsLayoutItemLegend(unittest.TestCase, LayoutItemTestCase):
@classmethod
def setUpClass(cls):
cls.item_class = QgsLayoutItemLegend
cls.report = "<h1>Python QgsLayoutItemLegend Tests</h1>\n"

def setUp(self):
self.report = "<h1>Python QgsLayoutItemLegend Tests</h1>\n"

def tearDown(self):
@classmethod
def tearDownClass(cls):
report_file_path = "%s/qgistest.html" % QDir.tempPath()
with open(report_file_path, 'a') as report_file:
report_file.write(self.report)
report_file.write(cls.report)

def testInitialSizeSymbolMapUnits(self):
"""Test initial size of legend with a symbol size in map units"""
Expand Down Expand Up @@ -106,7 +105,7 @@ def testInitialSizeSymbolMapUnits(self):
'composer_legend_mapunits', layout)
checker.setControlPathPrefix("composer_legend")
result, message = checker.testLayout()
self.report += checker.report()
TestQgsLayoutItemLegend.report += checker.report()
self.assertTrue(result, message)

# resize with non-top-left reference point
Expand Down Expand Up @@ -164,7 +163,7 @@ def testResizeWithMapContent(self):
'composer_legend_size_content', layout)
checker.setControlPathPrefix("composer_legend")
result, message = checker.testLayout()
self.report += checker.report()
TestQgsLayoutItemLegend.report += checker.report()
self.assertTrue(result, message)

QgsProject.instance().removeMapLayers([point_layer.id()])
Expand Down Expand Up @@ -207,7 +206,7 @@ def testResizeWithMapContentNoDoublePaint(self):
'composer_legend_size_content_no_double_paint', layout)
checker.setControlPathPrefix("composer_legend")
result, message = checker.testLayout()
self.report += checker.report()
TestQgsLayoutItemLegend.report += checker.report()
self.assertTrue(result, message)

def testResizeDisabled(self):
Expand Down Expand Up @@ -249,7 +248,7 @@ def testResizeDisabled(self):
'composer_legend_noresize', layout)
checker.setControlPathPrefix("composer_legend")
result, message = checker.testLayout()
self.report += checker.report()
TestQgsLayoutItemLegend.report += checker.report()
self.assertTrue(result, message)

QgsProject.instance().removeMapLayers([point_layer.id()])
Expand Down Expand Up @@ -293,7 +292,7 @@ def testResizeDisabledCrop(self):
'composer_legend_noresize_crop', layout)
checker.setControlPathPrefix("composer_legend")
result, message = checker.testLayout()
self.report += checker.report()
TestQgsLayoutItemLegend.report += checker.report()
self.assertTrue(result, message)

QgsProject.instance().removeMapLayers([point_layer.id()])
Expand Down Expand Up @@ -419,7 +418,7 @@ def testExpressionInText(self):
'composer_legend_expressions', layout)
checker.setControlPathPrefix("composer_legend")
result, message = checker.testLayout()
self.report += checker.report()
TestQgsLayoutItemLegend.report += checker.report()
self.assertTrue(result, message)

QgsProject.instance().removeMapLayers([point_layer.id()])
Expand Down Expand Up @@ -667,7 +666,67 @@ def testLegendRenderWithMapTheme(self):
'composer_legend_theme', layout)
checker.setControlPathPrefix("composer_legend")
result, message = checker.testLayout()
self.report += checker.report()
TestQgsLayoutItemLegend.report += checker.report()
self.assertTrue(result, message)

QgsProject.instance().clear()

def testLegendRenderLinkedMapScale(self):
"""Test rendering legends linked to maps follow scale correctly"""
QgsProject.instance().removeAllMapLayers()

line_path = os.path.join(TEST_DATA_DIR, 'lines.shp')
line_layer = QgsVectorLayer(line_path, 'lines', 'ogr')
QgsProject.instance().clear()
QgsProject.instance().addMapLayers([line_layer])

line_symbol = QgsLineSymbol.createSimple({'color': '#ff0000', 'width_unit': 'mapunits', 'width': '0.0001'})
line_layer.setRenderer(QgsSingleSymbolRenderer(line_symbol))

layout = QgsLayout(QgsProject.instance())
layout.initializeDefaults()

map1 = QgsLayoutItemMap(layout)
map1.attemptSetSceneRect(QRectF(20, 20, 80, 80))
map1.setFrameEnabled(True)
map1.setLayers([line_layer])
layout.addLayoutItem(map1)
map1.setExtent(line_layer.extent())
map1.setScale(2000)

map2 = QgsLayoutItemMap(layout)
map2.attemptSetSceneRect(QRectF(20, 120, 80, 80))
map2.setFrameEnabled(True)
map2.setLayers([line_layer])
layout.addLayoutItem(map2)
map2.setExtent(line_layer.extent())
map2.setScale(5000)

legend = QgsLayoutItemLegend(layout)
legend.setTitle("Legend")
legend.attemptSetSceneRect(QRectF(120, 20, 80, 80))
legend.setFrameEnabled(True)
legend.setFrameStrokeWidth(QgsLayoutMeasurement(2))
legend.setBackgroundColor(QColor(200, 200, 200))
legend.setTitle('')
layout.addLayoutItem(legend)
legend.setLinkedMap(map1)

legend2 = QgsLayoutItemLegend(layout)
legend2.setTitle("Legend")
legend2.attemptSetSceneRect(QRectF(120, 120, 80, 80))
legend2.setFrameEnabled(True)
legend2.setFrameStrokeWidth(QgsLayoutMeasurement(2))
legend2.setBackgroundColor(QColor(200, 200, 200))
legend2.setTitle('')
layout.addLayoutItem(legend2)
legend2.setLinkedMap(map2)

checker = QgsLayoutChecker(
'composer_legend_scale_map', layout)
checker.setControlPathPrefix("composer_legend")
result, message = checker.testLayout()
TestQgsLayoutItemLegend.report += checker.report()
self.assertTrue(result, message)

QgsProject.instance().clear()
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 426ee21

Please sign in to comment.