Skip to content

Commit

Permalink
Don't draw items which are a clip source for a map
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Jul 28, 2020
1 parent 2f3258c commit c5b3443
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 0 deletions.
7 changes: 7 additions & 0 deletions python/core/auto_generated/layout/qgslayoututils.sip.in
Expand Up @@ -244,6 +244,13 @@ This method will return an optimal round number which falls within the given ran
the largest "pretty" number possible.

.. versionadded:: 3.10
%End

static bool itemIsAClippingSource( const QgsLayoutItem *item );
%Docstring
Returns ``True`` if an ``item`` is a clipping item for another layout item.

.. versionadded:: 3.16
%End

};
Expand Down
3 changes: 3 additions & 0 deletions src/core/layout/qgslayoutitem.cpp
Expand Up @@ -589,6 +589,9 @@ bool QgsLayoutItem::shouldBlockUndoCommands() const

bool QgsLayoutItem::shouldDrawItem() const
{
if ( mLayout && QgsLayoutUtils::itemIsAClippingSource( this ) )
return false;

if ( !mLayout || mLayout->renderContext().isPreviewRender() )
{
//preview mode so OK to draw item
Expand Down
16 changes: 16 additions & 0 deletions src/core/layout/qgslayoututils.cpp
Expand Up @@ -461,6 +461,22 @@ double QgsLayoutUtils::calculatePrettySize( const double minimumSize, const doub
}
}

bool QgsLayoutUtils::itemIsAClippingSource( const QgsLayoutItem *item )
{
if ( !( item->itemFlags() & QgsLayoutItem::FlagProvidesClipPath ) )
return false; // not a clipping provider, so shortcut out

// current only maps can be clipped
QList< QgsLayoutItemMap * > maps;
item->layout()->layoutItems( maps );
for ( QgsLayoutItemMap *map : qgis::as_const( maps ) )
{
if ( map->itemClippingSettings()->isActive() && map->itemClippingSettings()->sourceItem() == item )
return true;
}
return false;
}

double QgsLayoutUtils::pointsToMM( const double pointSize )
{
//conversion to mm based on 1 point = 1/72 inch
Expand Down
7 changes: 7 additions & 0 deletions src/core/layout/qgslayoututils.h
Expand Up @@ -232,6 +232,13 @@ class CORE_EXPORT QgsLayoutUtils
*/
static double calculatePrettySize( double minimumSize, double maximumSize );

/**
* Returns TRUE if an \a item is a clipping item for another layout item.
*
* \since QGIS 3.16
*/
static bool itemIsAClippingSource( const QgsLayoutItem *item );

private:

//! Scale factor for upscaling fontsize and downscaling painter
Expand Down
60 changes: 60 additions & 0 deletions tests/src/python/test_qgslayoutmap.py
Expand Up @@ -662,6 +662,66 @@ def testClippingOverview(self):
self.report += checker.report()
self.assertTrue(result, message)

def testClippingHideClipSource(self):
"""
When an item is set to be the clip source, it shouldn't render anything itself
"""
format = QgsTextFormat()
format.setFont(QgsFontUtils.getStandardTestFont("Bold"))
format.setSize(30)
format.setNamedStyle("Bold")
format.setColor(QColor(0, 0, 0))
settings = QgsPalLayerSettings()
settings.setFormat(format)
settings.fieldName = "'XXXX'"
settings.isExpression = True
settings.placement = QgsPalLayerSettings.OverPoint

vl = QgsVectorLayer("Polygon?crs=epsg:4326&field=id:integer", "vl", "memory")

props = {"color": "127,255,127", 'outline_style': 'solid', 'outline_width': '1', 'outline_color': '0,0,255'}
fillSymbol = QgsFillSymbol.createSimple(props)
renderer = QgsSingleSymbolRenderer(fillSymbol)
vl.setRenderer(renderer)

f = QgsFeature(vl.fields(), 1)
for x in range(0, 15, 3):
for y in range(0, 15, 3):
f.setGeometry(QgsGeometry(QgsPoint(x, y)).buffer(1, 3))
vl.dataProvider().addFeature(f)

vl.setLabeling(QgsVectorLayerSimpleLabeling(settings))
vl.setLabelsEnabled(True)

p = QgsProject()

p.addMapLayer(vl)
layout = QgsLayout(p)
layout.initializeDefaults()
p.setCrs(QgsCoordinateReferenceSystem('EPSG:4326'))
map = QgsLayoutItemMap(layout)
map.attemptSetSceneRect(QRectF(10, 10, 180, 180))
map.setFrameEnabled(True)
map.zoomToExtent(vl.extent())
map.setLayers([vl])
layout.addLayoutItem(map)

shape = QgsLayoutItemShape(layout)
layout.addLayoutItem(shape)
shape.setShapeType(QgsLayoutItemShape.Ellipse)
shape.attemptSetSceneRect(QRectF(10, 10, 180, 180))

map.itemClippingSettings().setEnabled(True)
map.itemClippingSettings().setSourceItem(shape)
map.itemClippingSettings().setForceLabelsInsideClipPath(False)
map.itemClippingSettings().setFeatureClippingType(QgsMapClippingRegion.FeatureClippingType.ClipToIntersection)

checker = QgsLayoutChecker('composermap_itemclip_nodrawsource', layout)
checker.setControlPathPrefix("composer_map")
result, message = checker.testLayout()
self.report += checker.report()
self.assertTrue(result, message)


if __name__ == '__main__':
unittest.main()

0 comments on commit c5b3443

Please sign in to comment.